Commit caa84b81 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #684 from kmod/tiering2

tiering refactoring
parents 0915db4e a87e2eaf
......@@ -79,7 +79,7 @@ class ASTInterpreter : public Box {
public:
typedef ContiguousMap<InternedString, Box*> SymMap;
ASTInterpreter(CompiledFunction* compiled_function);
ASTInterpreter(CLFunction* clfunc);
void initArguments(int nargs, BoxedClosure* closure, BoxedGenerator* generator, Box* arg1, Box* arg2, Box* arg3,
Box** args);
......@@ -155,7 +155,7 @@ private:
CFGBlock* next_block, *current_block;
AST_stmt* current_inst;
CompiledFunction* compiled_func;
CLFunction* clfunc;
SourceInfo* source_info;
ScopeInfo* scope_info;
PhiAnalysis* phis;
......@@ -185,7 +185,7 @@ public:
return globals;
}
CompiledFunction* getCF() { return compiled_func; }
CLFunction* getCL() { return clfunc; }
FrameInfo* getFrameInfo() { return &frame_info; }
BoxedClosure* getPassedClosure() { return passed_closure; }
const SymMap& getSymbolTable() { return sym_table; }
......@@ -263,11 +263,11 @@ void ASTInterpreter::gcHandler(GCVisitor* visitor, Box* box) {
interp->frame_info.gcVisit(visitor);
}
ASTInterpreter::ASTInterpreter(CompiledFunction* compiled_function)
ASTInterpreter::ASTInterpreter(CLFunction* clfunc)
: current_block(0),
current_inst(0),
compiled_func(compiled_function),
source_info(compiled_function->clfunc->source.get()),
clfunc(clfunc),
source_info(clfunc->source.get()),
scope_info(0),
phis(NULL),
last_exception(NULL, NULL, NULL),
......@@ -279,10 +279,6 @@ ASTInterpreter::ASTInterpreter(CompiledFunction* compiled_function)
globals(0),
frame_addr(0) {
CLFunction* f = compiled_function->clfunc;
if (!source_info->cfg)
source_info->cfg = computeCFG(f->source.get(), f->source->body);
scope_info = source_info->getScopeInfo();
assert(scope_info);
......@@ -300,7 +296,7 @@ void ASTInterpreter::initArguments(int nargs, BoxedClosure* _closure, BoxedGener
for (int i = 3; i < nargs; ++i)
argsArray.push_back(args[i - 3]);
const ParamNames& param_names = compiled_func->clfunc->param_names;
const ParamNames& param_names = clfunc->param_names;
int i = 0;
for (auto& name : param_names.args) {
......@@ -345,7 +341,7 @@ void ASTInterpreter::startJITing(CFGBlock* block, int exit_offset) {
assert(ENABLE_BASELINEJIT);
assert(!jit);
auto& code_blocks = compiled_func->code_blocks;
auto& code_blocks = clfunc->code_blocks;
JitCodeBlock* code_block = NULL;
if (!code_blocks.empty())
code_block = code_blocks[code_blocks.size() - 1].get();
......@@ -387,7 +383,7 @@ Box* ASTInterpreter::execJITedBlock(CFGBlock* b) {
if (stmt->type != AST_TYPE::Invoke)
throw e;
auto source = getCF()->clfunc->source.get();
auto source = getCL()->source.get();
exceptionCaughtInInterpreter(LineInfo(stmt->lineno, stmt->col_offset, source->fn, source->getName()), &e);
next_block = ((AST_Invoke*)stmt)->exc_dest;
......@@ -412,7 +408,7 @@ Value ASTInterpreter::executeInner(ASTInterpreter& interpreter, CFGBlock* start_
start_block = interpreter.source_info->cfg->getStartingBlock();
start_at = start_block->body[0];
if (ENABLE_BASELINEJIT && interpreter.compiled_func->times_called >= REOPT_THRESHOLD_INTERPRETER
if (ENABLE_BASELINEJIT && interpreter.clfunc->times_interpreted >= REOPT_THRESHOLD_INTERPRETER
&& !start_block->code)
should_jit = true;
}
......@@ -475,6 +471,16 @@ Value ASTInterpreter::executeInner(ASTInterpreter& interpreter, CFGBlock* start_
Value ASTInterpreter::execute(ASTInterpreter& interpreter, CFGBlock* start_block, AST_stmt* start_at) {
UNAVOIDABLE_STAT_TIMER(t0, "us_timer_in_interpreter");
// Note: due to some (avoidable) restrictions, this check is pretty constrained in where
// it can go, due to the fact that it can throw an exception.
// It can't go in the ASTInterpreter constructor, since that will cause the C++ runtime to
// delete the partially-constructed memory which we don't currently handle. It can't go into
// executeInner since we want the SyntaxErrors to happen *before* the stack frame is entered.
// (For instance, throwing the exception will try to fetch the current statement, but we determine
// that by looking at the cfg.)
if (!interpreter.source_info->cfg)
interpreter.source_info->cfg = computeCFG(interpreter.source_info, interpreter.source_info->body);
RegisterHelper frame_registerer;
return executeInner(interpreter, start_block, start_at, &frame_registerer);
}
......@@ -640,7 +646,7 @@ Value ASTInterpreter::visit_branch(AST_Branch* node) {
}
Value ASTInterpreter::visit_jump(AST_Jump* node) {
bool backedge = node->target->idx < current_block->idx && compiled_func;
bool backedge = node->target->idx < current_block->idx;
if (backedge) {
threading::allowGLReadPreemption();
......@@ -681,7 +687,7 @@ Box* ASTInterpreter::doOSR(AST_Jump* node) {
LivenessAnalysis* liveness = source_info->getLiveness();
std::unique_ptr<PhiAnalysis> phis
= computeRequiredPhis(compiled_func->clfunc->param_names, source_info->cfg, liveness, scope_info);
= computeRequiredPhis(clfunc->param_names, source_info->cfg, liveness, scope_info);
std::vector<InternedString> dead_symbols;
for (auto& it : sym_table) {
......@@ -696,9 +702,7 @@ Box* ASTInterpreter::doOSR(AST_Jump* node) {
sym_table.erase(dead);
const OSREntryDescriptor* found_entry = nullptr;
for (auto& p : compiled_func->clfunc->osr_versions) {
if (p.first->cf != compiled_func)
continue;
for (auto& p : clfunc->osr_versions) {
if (p.first->backedge != node)
continue;
......@@ -748,7 +752,7 @@ Box* ASTInterpreter::doOSR(AST_Jump* node) {
sorted_symbol_table[source_info->getInternedStrings().get(FRAME_INFO_PTR_NAME)] = (Box*)&frame_info;
if (found_entry == nullptr) {
OSREntryDescriptor* entry = OSREntryDescriptor::create(compiled_func, node);
OSREntryDescriptor* entry = OSREntryDescriptor::create(clfunc, node);
for (auto& it : sorted_symbol_table) {
if (isIsDefinedName(it.first))
......@@ -768,7 +772,7 @@ Box* ASTInterpreter::doOSR(AST_Jump* node) {
found_entry = entry;
}
OSRExit exit(compiled_func, found_entry);
OSRExit exit(found_entry);
std::vector<Box*, StlCompatAllocator<Box*>> arg_array;
for (auto& it : sorted_symbol_table) {
......@@ -781,13 +785,8 @@ Box* ASTInterpreter::doOSR(AST_Jump* node) {
Box* r = partial_func->call(std::get<0>(arg_tuple), std::get<1>(arg_tuple), std::get<2>(arg_tuple),
std::get<3>(arg_tuple));
// This is one of the few times that we are allowed to have an invalid value in a Box* Value.
// Check for it, and return as an int so that we don't trigger a potential assert when
// creating the Value.
if (compiled_func->getReturnType() != VOID)
assert(r);
return r ? r : None;
assert(r);
return r;
}
Value ASTInterpreter::visit_invoke(AST_Invoke* node) {
......@@ -803,7 +802,7 @@ Value ASTInterpreter::visit_invoke(AST_Invoke* node) {
} catch (ExcInfo e) {
abortJITing();
auto source = getCF()->clfunc->source.get();
auto source = getCL()->source.get();
exceptionCaughtInInterpreter(LineInfo(node->lineno, node->col_offset, source->fn, source->getName()), &e);
next_block = node->exc_dest;
......@@ -1034,7 +1033,7 @@ Box* ASTInterpreter::createFunction(AST* node, AST_arguments* args, const std::v
}
Box* passed_globals = NULL;
if (!getCF()->clfunc->source->scoping->areGlobalsFromModule())
if (!getCL()->source->scoping->areGlobalsFromModule())
passed_globals = globals;
return boxCLFunction(cl, closure, passed_globals, u.il);
}
......@@ -1083,7 +1082,7 @@ Value ASTInterpreter::visit_makeClass(AST_MakeClass* mkclass) {
CLFunction* cl = wrapFunction(node, nullptr, node->body, source_info);
Box* passed_globals = NULL;
if (!getCF()->clfunc->source->scoping->areGlobalsFromModule())
if (!getCL()->source->scoping->areGlobalsFromModule())
passed_globals = globals;
Box* attrDict = runtimeCall(boxCLFunction(cl, closure, passed_globals, {}), ArgPassSpec(0), 0, 0, 0, 0, 0);
......@@ -1661,17 +1660,45 @@ void ASTInterpreterJitInterface::setLocalHelper(void* _interpreter, InternedStri
const void* interpreter_instr_addr = (void*)&ASTInterpreter::executeInner;
Box* astInterpretFunction(CompiledFunction* cf, int nargs, Box* closure, Box* generator, Box* globals, Box* arg1,
Box* astInterpretFunction(CLFunction* clfunc, int nargs, Box* closure, Box* generator, Box* globals, Box* arg1,
Box* arg2, Box* arg3, Box** args) {
UNAVOIDABLE_STAT_TIMER(t0, "us_timer_in_interpreter");
assert((!globals) == cf->clfunc->source->scoping->areGlobalsFromModule());
SourceInfo* source_info = clfunc->source.get();
assert((!globals) == source_info->scoping->areGlobalsFromModule());
bool can_reopt = ENABLE_REOPT && !FORCE_INTERPRETER && (globals == NULL);
int num_blocks = cf->clfunc->source->cfg->blocks.size();
// If the cfg hasn't been computed yet, just conservatively say that it will be a big function.
// It shouldn't matter, since the cfg should only be NULL if this is the first execution of this
// function.
int num_blocks = source_info->cfg ? source_info->cfg->blocks.size() : 10000;
int threshold = num_blocks <= 20 ? (REOPT_THRESHOLD_BASELINE / 3) : REOPT_THRESHOLD_BASELINE;
if (unlikely(can_reopt && cf->times_called > threshold)) {
if (unlikely(can_reopt && (FORCE_OPTIMIZE || !ENABLE_INTERPRETER || clfunc->times_interpreted > threshold))) {
assert(!globals);
CompiledFunction* optimized = reoptCompiledFuncInternal(cf);
clfunc->times_interpreted = 0;
EffortLevel new_effort = EffortLevel::MODERATE;
if (FORCE_OPTIMIZE)
new_effort = EffortLevel::MAXIMAL;
std::vector<ConcreteCompilerType*> arg_types;
for (int i = 0; i < nargs; i++) {
Box* arg = getArg(i, arg1, arg2, arg3, args);
assert(arg); // only builtin functions can pass NULL args
// TODO: reenable argument-type specialization
arg_types.push_back(UNKNOWN);
// arg_types.push_back(typeFromClass(arg->cls));
}
FunctionSpecialization* spec = new FunctionSpecialization(UNKNOWN, arg_types);
// this also pushes the new CompiledVersion to the back of the version list:
CompiledFunction* optimized = compileFunction(clfunc, spec, new_effort, NULL);
clfunc->dependent_interp_callsites.invalidateAll();
if (closure && generator)
return optimized->closure_generator_call((BoxedClosure*)closure, (BoxedGenerator*)generator, arg1, arg2,
arg3, args);
......@@ -1682,16 +1709,15 @@ Box* astInterpretFunction(CompiledFunction* cf, int nargs, Box* closure, Box* ge
return optimized->call(arg1, arg2, arg3, args);
}
++cf->times_called;
ASTInterpreter* interpreter = new ASTInterpreter(cf);
++clfunc->times_interpreted;
ASTInterpreter* interpreter = new ASTInterpreter(clfunc);
ScopeInfo* scope_info = cf->clfunc->source->getScopeInfo();
SourceInfo* source_info = cf->clfunc->source.get();
ScopeInfo* scope_info = clfunc->source->getScopeInfo();
if (unlikely(scope_info->usesNameLookup())) {
interpreter->setBoxedLocals(new BoxedDict());
}
assert((!globals) == cf->clfunc->source->scoping->areGlobalsFromModule());
assert((!globals) == clfunc->source->scoping->areGlobalsFromModule());
if (globals) {
interpreter->setGlobals(globals);
} else {
......@@ -1704,17 +1730,17 @@ Box* astInterpretFunction(CompiledFunction* cf, int nargs, Box* closure, Box* ge
return v.o ? v.o : None;
}
Box* astInterpretFunctionEval(CompiledFunction* cf, Box* globals, Box* boxedLocals) {
++cf->times_called;
Box* astInterpretFunctionEval(CLFunction* clfunc, Box* globals, Box* boxedLocals) {
++clfunc->times_interpreted;
ASTInterpreter* interpreter = new ASTInterpreter(cf);
ASTInterpreter* interpreter = new ASTInterpreter(clfunc);
interpreter->initArguments(0, NULL, NULL, NULL, NULL, NULL, NULL);
interpreter->setBoxedLocals(boxedLocals);
ScopeInfo* scope_info = cf->clfunc->source->getScopeInfo();
SourceInfo* source_info = cf->clfunc->source.get();
ScopeInfo* scope_info = clfunc->source->getScopeInfo();
SourceInfo* source_info = clfunc->source.get();
assert(!cf->clfunc->source->scoping->areGlobalsFromModule());
assert(!clfunc->source->scoping->areGlobalsFromModule());
assert(globals);
interpreter->setGlobals(globals);
......@@ -1723,19 +1749,19 @@ Box* astInterpretFunctionEval(CompiledFunction* cf, Box* globals, Box* boxedLoca
return v.o ? v.o : None;
}
Box* astInterpretFrom(CompiledFunction* cf, AST_expr* after_expr, AST_stmt* enclosing_stmt, Box* expr_val,
Box* astInterpretFrom(CLFunction* clfunc, AST_expr* after_expr, AST_stmt* enclosing_stmt, Box* expr_val,
FrameStackState frame_state) {
assert(cf);
assert(clfunc);
assert(enclosing_stmt);
assert(frame_state.locals);
assert(after_expr);
assert(expr_val);
ASTInterpreter* interpreter = new ASTInterpreter(cf);
ASTInterpreter* interpreter = new ASTInterpreter(clfunc);
ScopeInfo* scope_info = cf->clfunc->source->getScopeInfo();
SourceInfo* source_info = cf->clfunc->source.get();
assert(cf->clfunc->source->scoping->areGlobalsFromModule());
ScopeInfo* scope_info = clfunc->source->getScopeInfo();
SourceInfo* source_info = clfunc->source.get();
assert(clfunc->source->scoping->areGlobalsFromModule());
interpreter->setGlobals(source_info->parent_module);
for (const auto& p : frame_state.locals->d) {
......@@ -1748,7 +1774,7 @@ Box* astInterpretFrom(CompiledFunction* cf, AST_expr* after_expr, AST_stmt* encl
} else if (name == CREATED_CLOSURE_NAME) {
interpreter->setCreatedClosure(p.second);
} else {
InternedString interned = cf->clfunc->source->getInternedStrings().get(name);
InternedString interned = clfunc->source->getInternedStrings().get(name);
interpreter->addSymbol(interned, p.second, false);
}
}
......@@ -1784,7 +1810,7 @@ Box* astInterpretFrom(CompiledFunction* cf, AST_expr* after_expr, AST_stmt* encl
if (start_block == NULL) {
// TODO innefficient
for (auto block : cf->clfunc->source->cfg->blocks) {
for (auto block : clfunc->source->cfg->blocks) {
int n = block->body.size();
for (int i = 0; i < n; i++) {
if (block->body[i] == enclosing_stmt) {
......@@ -1820,10 +1846,10 @@ Box* getGlobalsForInterpretedFrame(void* frame_ptr) {
return interpreter->getGlobals();
}
CompiledFunction* getCFForInterpretedFrame(void* frame_ptr) {
CLFunction* getCLForInterpretedFrame(void* frame_ptr) {
ASTInterpreter* interpreter = s_interpreterMap[frame_ptr];
assert(interpreter);
return interpreter->getCF();
return interpreter->getCL();
}
FrameInfo* getFrameInfoForInterpretedFrame(void* frame_ptr) {
......
......@@ -29,7 +29,7 @@ class AST_Jump;
class Box;
class BoxedClosure;
class BoxedDict;
struct CompiledFunction;
struct CLFunction;
struct LineInfo;
extern const void* interpreter_instr_addr;
......@@ -72,15 +72,15 @@ struct Value {
};
void setupInterpreter();
Box* astInterpretFunction(CompiledFunction* f, int nargs, Box* closure, Box* generator, Box* globals, Box* arg1,
Box* arg2, Box* arg3, Box** args);
Box* astInterpretFunctionEval(CompiledFunction* cf, Box* globals, Box* boxedLocals);
Box* astInterpretFrom(CompiledFunction* cf, AST_expr* after_expr, AST_stmt* enclosing_stmt, Box* expr_val,
Box* astInterpretFunction(CLFunction* f, int nargs, Box* closure, Box* generator, Box* globals, Box* arg1, Box* arg2,
Box* arg3, Box** args);
Box* astInterpretFunctionEval(CLFunction* cf, Box* globals, Box* boxedLocals);
Box* astInterpretFrom(CLFunction* cf, AST_expr* after_expr, AST_stmt* enclosing_stmt, Box* expr_val,
FrameStackState frame_state);
AST_stmt* getCurrentStatementForInterpretedFrame(void* frame_ptr);
Box* getGlobalsForInterpretedFrame(void* frame_ptr);
CompiledFunction* getCFForInterpretedFrame(void* frame_ptr);
CLFunction* getCLForInterpretedFrame(void* frame_ptr);
struct FrameInfo;
FrameInfo* getFrameInfoForInterpretedFrame(void* frame_ptr);
BoxedClosure* passedClosureForInterpretedFrame(void* frame_ptr);
......
......@@ -27,6 +27,7 @@
#include "analysis/function_analysis.h"
#include "analysis/scoping_analysis.h"
#include "codegen/baseline_jit.h"
#include "codegen/compvars.h"
#include "core/ast.h"
#include "core/util.h"
......@@ -35,6 +36,27 @@ namespace pyston {
DS_DEFINE_RWLOCK(codegen_rwlock);
CLFunction::CLFunction(int num_args, int num_defaults, bool takes_varargs, bool takes_kwargs,
std::unique_ptr<SourceInfo> source)
: paramspec(num_args, num_defaults, takes_varargs, takes_kwargs),
source(std::move(source)),
param_names(this->source->ast, this->source->getInternedStrings()),
always_use_version(NULL),
code_obj(NULL),
times_interpreted(0) {
assert(num_args >= num_defaults);
}
CLFunction::CLFunction(int num_args, int num_defaults, bool takes_varargs, bool takes_kwargs,
const ParamNames& param_names)
: paramspec(num_args, num_defaults, takes_varargs, takes_kwargs),
source(nullptr),
param_names(param_names),
always_use_version(NULL),
code_obj(NULL),
times_interpreted(0) {
assert(num_args >= num_defaults);
}
SourceInfo::SourceInfo(BoxedModule* m, ScopingAnalysis* scoping, FutureFlags future_flags, AST* ast,
std::vector<AST_stmt*> body, std::string fn)
: parent_module(m),
......
......@@ -249,7 +249,7 @@ public:
// var->getValue()->dump(); llvm::errs() << '\n';
// ptr->dump(); llvm::errs() << '\n';
// converted->getValue()->dump(); llvm::errs() << '\n';
bool do_patchpoint = ENABLE_ICSETATTRS && !info.isInterpreted();
bool do_patchpoint = ENABLE_ICSETATTRS;
if (do_patchpoint) {
ICSetupInfo* pp = createSetattrIC(info.getTypeRecorder());
......@@ -269,7 +269,7 @@ public:
llvm::Constant* ptr = embedRelocatablePtr(attr, g.llvm_boxedstring_type_ptr);
// TODO
// bool do_patchpoint = ENABLE_ICDELATTRS && !info.isInterpreted();
// bool do_patchpoint = ENABLE_ICDELATTRS;
bool do_patchpoint = false;
if (do_patchpoint) {
......@@ -317,7 +317,7 @@ public:
}
ConcreteCompilerVariable* len(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var) override {
bool do_patchpoint = ENABLE_ICGENERICS && !info.isInterpreted();
bool do_patchpoint = ENABLE_ICGENERICS;
llvm::Value* rtn;
if (do_patchpoint) {
ICSetupInfo* pp = createGenericIC(info.getTypeRecorder(), true, 256);
......@@ -337,7 +337,7 @@ public:
CompilerVariable* slice) override {
ConcreteCompilerVariable* converted_slice = slice->makeConverted(emitter, slice->getBoxType());
bool do_patchpoint = ENABLE_ICGETITEMS && !info.isInterpreted();
bool do_patchpoint = ENABLE_ICGETITEMS;
llvm::Value* rtn;
if (do_patchpoint) {
ICSetupInfo* pp = createGetitemIC(info.getTypeRecorder());
......@@ -414,7 +414,7 @@ public:
ConcreteCompilerVariable* converted_rhs = rhs->makeConverted(emitter, rhs->getBoxType());
llvm::Value* rtn;
bool do_patchpoint = ENABLE_ICBINEXPS && !info.isInterpreted();
bool do_patchpoint = ENABLE_ICBINEXPS;
llvm::Value* rt_func;
void* rt_func_addr;
......@@ -495,7 +495,7 @@ CompilerVariable* UnknownType::getattr(IREmitter& emitter, const OpInfo& info, C
raw_func = (void*)pyston::getattr;
}
bool do_patchpoint = ENABLE_ICGETATTRS && !info.isInterpreted();
bool do_patchpoint = ENABLE_ICGETATTRS;
if (do_patchpoint) {
ICSetupInfo* pp = createGetattrIC(info.getTypeRecorder());
......@@ -551,19 +551,13 @@ static ConcreteCompilerVariable* _call(IREmitter& emitter, const OpInfo& info, l
if (args.size() >= 4) {
llvm::Value* arg_array;
if (info.isInterpreted()) {
llvm::Value* n_bytes = getConstantInt((args.size() - 3) * sizeof(Box*), g.i64);
mallocsave = emitter.getBuilder()->CreateCall(g.funcs.malloc, n_bytes);
arg_array = emitter.getBuilder()->CreateBitCast(mallocsave, g.llvm_value_type_ptr->getPointerTo());
} else {
llvm::Value* n_varargs = getConstantInt(args.size() - 3, g.i64);
llvm::Value* n_varargs = getConstantInt(args.size() - 3, g.i64);
// Don't use the IRBuilder since we want to specifically put this in the entry block so it only gets called
// once.
// TODO we could take this further and use the same alloca for all function calls?
llvm::Instruction* insertion_point = emitter.currentFunction()->func->getEntryBlock().getFirstInsertionPt();
arg_array = new llvm::AllocaInst(g.llvm_value_type_ptr, n_varargs, "arg_scratch", insertion_point);
}
// Don't use the IRBuilder since we want to specifically put this in the entry block so it only gets called
// once.
// TODO we could take this further and use the same alloca for all function calls?
llvm::Instruction* insertion_point = emitter.currentFunction()->func->getEntryBlock().getFirstInsertionPt();
arg_array = new llvm::AllocaInst(g.llvm_value_type_ptr, n_varargs, "arg_scratch", insertion_point);
for (int i = 3; i < args.size(); i++) {
llvm::Value* ptr = emitter.getBuilder()->CreateConstGEP1_32(arg_array, i - 3);
......@@ -590,8 +584,7 @@ static ConcreteCompilerVariable* _call(IREmitter& emitter, const OpInfo& info, l
// for (auto a : llvm_args)
// a->dump();
bool do_patchpoint = ENABLE_ICCALLSITES && !info.isInterpreted()
&& (func_addr == runtimeCall || func_addr == pyston::callattr);
bool do_patchpoint = ENABLE_ICCALLSITES && (func_addr == runtimeCall || func_addr == pyston::callattr);
if (do_patchpoint) {
assert(func_addr);
......@@ -685,7 +678,7 @@ CompilerVariable* UnknownType::callattr(IREmitter& emitter, const OpInfo& info,
}
ConcreteCompilerVariable* UnknownType::nonzero(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var) {
bool do_patchpoint = ENABLE_ICNONZEROS && !info.isInterpreted();
bool do_patchpoint = ENABLE_ICNONZEROS;
llvm::Value* rtn_val;
if (do_patchpoint) {
ICSetupInfo* pp = createNonzeroIC(info.getTypeRecorder());
......@@ -702,7 +695,7 @@ ConcreteCompilerVariable* UnknownType::nonzero(IREmitter& emitter, const OpInfo&
}
ConcreteCompilerVariable* UnknownType::hasnext(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var) {
bool do_patchpoint = ENABLE_ICS && !info.isInterpreted();
bool do_patchpoint = ENABLE_ICS;
do_patchpoint = false; // we are currently using runtime ics for this
llvm::Value* rtn_val;
if (do_patchpoint) {
......@@ -1573,7 +1566,6 @@ public:
}
assert(found);
assert(!cf->is_interpreted);
assert(cf->code);
std::vector<llvm::Type*> arg_types;
......@@ -1965,14 +1957,6 @@ CompilerVariable* makeStr(BoxedString* s) {
return new ValuedCompilerVariable<BoxedString*>(STR_CONSTANT, s, true);
}
class VoidType : public ConcreteCompilerType {
public:
llvm::Type* llvmType() override { return g.void_; }
Box* deserializeFromFrame(const FrameVals& vals) override { abort(); }
};
ConcreteCompilerType* VOID = new VoidType();
ConcreteCompilerType* typeFromClass(BoxedClass* c) {
assert(c);
return NormalObjectType::fromClass(c);
......
......@@ -579,11 +579,7 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
// printf("%ld\n", args.size());
llvm::CallInst* postcall = emitter->getBuilder()->CreateCall(bitcast_r, args);
postcall->setTailCall(true);
if (rtn_type == VOID) {
emitter->getBuilder()->CreateRetVoid();
} else {
emitter->getBuilder()->CreateRet(postcall);
}
emitter->getBuilder()->CreateRet(postcall);
emitter->getBuilder()->SetInsertPoint(llvm_entry_blocks[source->cfg->getStartingBlock()]);
}
......@@ -941,16 +937,15 @@ static std::string getUniqueFunctionName(std::string nameprefix, EffortLevel eff
os << "_e" << (int)effort;
if (entry) {
os << "_osr" << entry->backedge->target->idx;
if (entry->cf->func)
os << "_from_" << entry->cf->func->getName().data();
}
os << '_' << num_functions;
num_functions++;
return os.str();
}
CompiledFunction* doCompile(SourceInfo* source, ParamNames* param_names, const OSREntryDescriptor* entry_descriptor,
EffortLevel effort, FunctionSpecialization* spec, std::string nameprefix) {
CompiledFunction* doCompile(CLFunction* clfunc, SourceInfo* source, ParamNames* param_names,
const OSREntryDescriptor* entry_descriptor, EffortLevel effort,
FunctionSpecialization* spec, std::string nameprefix) {
Timer _t("in doCompile");
Timer _t2;
long irgen_us = 0;
......@@ -1014,8 +1009,7 @@ CompiledFunction* doCompile(SourceInfo* source, ParamNames* param_names, const O
}
CompiledFunction* cf
= new CompiledFunction(NULL, spec, (effort == EffortLevel::INTERPRETED), NULL, effort, entry_descriptor);
CompiledFunction* cf = new CompiledFunction(NULL, spec, NULL, effort, entry_descriptor);
// Make sure that the instruction memory keeps the module object alive.
// TODO: implement this for real
......@@ -1065,7 +1059,7 @@ CompiledFunction* doCompile(SourceInfo* source, ParamNames* param_names, const O
else
phis = computeRequiredPhis(*param_names, source->cfg, liveness, source->getScopeInfo());
IRGenState irstate(cf, source, std::move(phis), param_names, getGCBuilder(), dbg_funcinfo);
IRGenState irstate(clfunc, cf, source, std::move(phis), param_names, getGCBuilder(), dbg_funcinfo);
emitBBs(&irstate, types, entry_descriptor, blocks);
......
......@@ -100,8 +100,9 @@ extern const std::string PASSED_GENERATOR_NAME;
InternedString getIsDefinedName(InternedString name, InternedStringPool& interned_strings);
bool isIsDefinedName(llvm::StringRef name);
CompiledFunction* doCompile(SourceInfo* source, ParamNames* param_names, const OSREntryDescriptor* entry_descriptor,
EffortLevel effort, FunctionSpecialization* spec, std::string nameprefix);
CompiledFunction* doCompile(CLFunction* clfunc, SourceInfo* source, ParamNames* param_names,
const OSREntryDescriptor* entry_descriptor, EffortLevel effort,
FunctionSpecialization* spec, std::string nameprefix);
// A common pattern is to branch based off whether a variable is defined but only if it is
// potentially-undefined. If it is potentially-undefined, we have to generate control-flow
......@@ -134,7 +135,6 @@ public:
OpInfo(EffortLevel effort, TypeRecorder* type_recorder, UnwindInfo unw_info)
: effort(effort), type_recorder(type_recorder), unw_info(unw_info) {}
bool isInterpreted() const { return effort == EffortLevel::INTERPRETED; }
TypeRecorder* getTypeRecorder() const { return type_recorder; }
};
}
......
......@@ -127,23 +127,14 @@ LivenessAnalysis* SourceInfo::getLiveness() {
return liveness_info.get();
}
EffortLevel initialEffort() {
if (FORCE_INTERPRETER)
return EffortLevel::INTERPRETED;
if (FORCE_OPTIMIZE)
return EffortLevel::MAXIMAL;
if (ENABLE_INTERPRETER)
return EffortLevel::INTERPRETED;
return EffortLevel::MODERATE;
}
static void compileIR(CompiledFunction* cf, EffortLevel effort) {
assert(cf);
assert(cf->func);
void* compiled = NULL;
cf->code = NULL;
if (effort > EffortLevel::INTERPRETED) {
{
Timer _t("to jit the IR");
#if LLVMREV < 215967
g.engine->addModule(cf->func->getParent());
......@@ -195,7 +186,7 @@ CompiledFunction* compileFunction(CLFunction* f, FunctionSpecialization* spec, E
ASSERT(f->versions.size() < 20, "%s %ld", name.c_str(), f->versions.size());
if (VERBOSITY("irgen") >= 2 || (VERBOSITY("irgen") == 1 && effort > EffortLevel::INTERPRETED)) {
if (VERBOSITY("irgen") >= 1) {
std::string s;
llvm::raw_string_ostream ss(s);
......@@ -233,13 +224,6 @@ CompiledFunction* compileFunction(CLFunction* f, FunctionSpecialization* spec, E
printf("%s", ss.str().c_str());
}
#ifndef NDEBUG
if (effort == EffortLevel::INTERPRETED) {
for (auto arg_type : spec->arg_types)
assert(arg_type == UNKNOWN);
}
#endif
// Do the analysis now if we had deferred it earlier:
if (source->cfg == NULL) {
source->cfg = computeCFG(source, source->body);
......@@ -247,17 +231,10 @@ CompiledFunction* compileFunction(CLFunction* f, FunctionSpecialization* spec, E
CompiledFunction* cf = 0;
if (effort == EffortLevel::INTERPRETED) {
assert(!entry_descriptor);
cf = new CompiledFunction(0, spec, true, NULL, effort, 0);
} else {
cf = doCompile(source, &f->param_names, entry_descriptor, effort, spec, name);
compileIR(cf, effort);
}
CompiledFunction* cf = doCompile(f, source, &f->param_names, entry_descriptor, effort, spec, name);
compileIR(cf, effort);
f->addVersion(cf);
assert(f->versions.size());
long us = _t.end();
static StatCounter us_compiling("us_compiling");
......@@ -270,13 +247,6 @@ CompiledFunction* compileFunction(CLFunction* f, FunctionSpecialization* spec, E
num_compiles.log();
switch (effort) {
case EffortLevel::INTERPRETED: {
static StatCounter us_compiling("us_compiling_0_interpreted");
us_compiling.log(us);
static StatCounter num_compiles("num_compiles_0_interpreted");
num_compiles.log();
break;
}
case EffortLevel::MODERATE: {
static StatCounter us_compiling("us_compiling_2_moderate");
us_compiling.log(us);
......@@ -299,7 +269,7 @@ CompiledFunction* compileFunction(CLFunction* f, FunctionSpecialization* spec, E
}
void compileAndRunModule(AST_Module* m, BoxedModule* bm) {
CompiledFunction* cf;
CLFunction* clfunc;
{ // scope for limiting the locked region:
LOCK_REGION(codegen_rwlock.asWrite());
......@@ -317,23 +287,12 @@ void compileAndRunModule(AST_Module* m, BoxedModule* bm) {
if (!bm->hasattr("__builtins__"))
bm->giveAttr("__builtins__", PyModule_GetDict(builtins_module));
CLFunction* cl_f = new CLFunction(0, 0, false, false, std::move(si));
EffortLevel effort = initialEffort();
assert(scoping->areGlobalsFromModule());
cf = compileFunction(cl_f, new FunctionSpecialization(VOID), effort, NULL);
assert(cf->clfunc->versions.size());
clfunc = new CLFunction(0, 0, false, false, std::move(si));
}
if (cf->is_interpreted) {
UNAVOIDABLE_STAT_TIMER(t0, "us_timer_interpreted_module_toplevel");
astInterpretFunction(cf, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
} else {
UNAVOIDABLE_STAT_TIMER(t1, "us_timer_jitted_module_toplevel");
((void (*)())cf->code)();
}
UNAVOIDABLE_STAT_TIMER(t0, "us_timer_interpreted_module_toplevel");
Box* r = astInterpretFunction(clfunc, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
assert(r == None);
}
Box* evalOrExec(CLFunction* cl, Box* globals, Box* boxedLocals) {
......@@ -341,24 +300,13 @@ Box* evalOrExec(CLFunction* cl, Box* globals, Box* boxedLocals) {
assert(globals && (globals->cls == module_cls || globals->cls == dict_cls));
// TODO Right now we only support going into an exec or eval through the
// intepretter, since the interpretter has a special function which lets
// us set the locals object. We should probably support it for optimized
// code as well, so we could use initialEffort() here instead of hard-coding
// INTERPRETED. This could actually be useful if we actually cache the parse
// results (since sometimes eval or exec might be called on constant strings).
EffortLevel effort = EffortLevel::INTERPRETED;
Box* doc_string = cl->source->getDocString();
if (doc_string != None) {
static BoxedString* doc_box = static_cast<BoxedString*>(PyString_InternFromString("__doc__"));
setGlobal(boxedLocals, doc_box, doc_string);
}
CompiledFunction* cf = compileFunction(cl, new FunctionSpecialization(VOID), effort, NULL);
assert(cf->clfunc->versions.size());
return astInterpretFunctionEval(cf, globals, boxedLocals);
return astInterpretFunctionEval(cl, globals, boxedLocals);
}
CLFunction* compileForEvalOrExec(AST* source, std::vector<AST_stmt*> body, std::string fn, PyCompilerFlags* flags) {
......@@ -502,10 +450,10 @@ Box* compile(Box* source, Box* fn, Box* type, Box** _args) {
if (dont_inherit) {
future_flags = arg_future_flags;
} else {
CompiledFunction* caller_cf = getTopCompiledFunction();
assert(caller_cf != NULL);
assert(caller_cf->clfunc->source != NULL);
FutureFlags caller_future_flags = caller_cf->clfunc->source->future_flags;
CLFunction* caller_cl = getTopPythonFunction();
assert(caller_cl != NULL);
assert(caller_cl->source != NULL);
FutureFlags caller_future_flags = caller_cl->source->future_flags;
future_flags = arg_future_flags | caller_future_flags;
}
......@@ -602,10 +550,10 @@ static Box* evalMain(Box* boxedCode, Box* globals, Box* locals, PyCompilerFlags*
}
Box* eval(Box* boxedCode, Box* globals, Box* locals) {
CompiledFunction* caller_cf = getTopCompiledFunction();
assert(caller_cf != NULL);
assert(caller_cf->clfunc->source != NULL);
FutureFlags caller_future_flags = caller_cf->clfunc->source->future_flags;
CLFunction* caller_cl = getTopPythonFunction();
assert(caller_cl != NULL);
assert(caller_cl->source != NULL);
FutureFlags caller_future_flags = caller_cl->source->future_flags;
PyCompilerFlags pcf;
pcf.cf_flags = caller_future_flags;
......@@ -742,13 +690,12 @@ void CompiledFunction::speculationFailed() {
}
}
CompiledFunction::CompiledFunction(llvm::Function* func, FunctionSpecialization* spec, bool is_interpreted, void* code,
EffortLevel effort, const OSREntryDescriptor* entry_descriptor)
CompiledFunction::CompiledFunction(llvm::Function* func, FunctionSpecialization* spec, void* code, EffortLevel effort,
const OSREntryDescriptor* entry_descriptor)
: clfunc(NULL),
func(func),
spec(spec),
entry_descriptor(entry_descriptor),
is_interpreted(is_interpreted),
code(code),
effort(effort),
times_called(0),
......@@ -758,9 +705,11 @@ CompiledFunction::CompiledFunction(llvm::Function* func, FunctionSpecialization*
}
ConcreteCompilerType* CompiledFunction::getReturnType() {
assert(((bool)spec) ^ ((bool)entry_descriptor));
if (spec)
return spec->rtn_type;
return entry_descriptor->cf->getReturnType();
else
return UNKNOWN;
}
/// Reoptimizes the given function version at the new effort level.
......@@ -809,18 +758,16 @@ CompiledFunction* compilePartialFuncInternal(OSRExit* exit) {
LOCK_REGION(codegen_rwlock.asWrite());
assert(exit);
assert(exit->parent_cf);
assert(exit->parent_cf->effort < EffortLevel::MAXIMAL);
stat_osrexits.log();
// if (VERBOSITY("irgen") >= 1) printf("In compilePartialFunc, handling %p\n", exit);
assert(exit->parent_cf->clfunc);
CompiledFunction*& new_cf = exit->parent_cf->clfunc->osr_versions[exit->entry];
CLFunction* clfunc = exit->entry->clfunc;
assert(clfunc);
CompiledFunction*& new_cf = clfunc->osr_versions[exit->entry];
if (new_cf == NULL) {
EffortLevel new_effort = exit->parent_cf->effort == EffortLevel::INTERPRETED ? EffortLevel::MODERATE
: EffortLevel::MAXIMAL;
CompiledFunction* compiled = compileFunction(exit->parent_cf->clfunc, NULL, new_effort, exit->entry);
EffortLevel new_effort = EffortLevel::MAXIMAL;
CompiledFunction* compiled = compileFunction(clfunc, NULL, new_effort, exit->entry);
assert(compiled == new_cf);
stat_osr_compiles.log();
......@@ -843,16 +790,9 @@ extern "C" CompiledFunction* reoptCompiledFuncInternal(CompiledFunction* cf) {
assert(cf->effort < EffortLevel::MAXIMAL);
assert(cf->clfunc->versions.size());
EffortLevel new_effort;
if (cf->effort == EffortLevel::INTERPRETED)
new_effort = EffortLevel::MODERATE;
else if (cf->effort == EffortLevel::MODERATE)
new_effort = EffortLevel::MAXIMAL;
else
RELEASE_ASSERT(0, "unknown effort: %d", cf->effort);
EffortLevel new_effort = EffortLevel::MAXIMAL;
CompiledFunction* new_cf = _doReopt(cf, new_effort);
assert(!new_cf->is_interpreted);
return new_cf;
}
......@@ -905,6 +845,6 @@ void addRTFunction(CLFunction* cl_f, void* f, ConcreteCompilerType* rtn_type,
#endif
FunctionSpecialization* spec = new FunctionSpecialization(processType(rtn_type), arg_types);
cl_f->addVersion(new CompiledFunction(NULL, spec, false, f, EffortLevel::MAXIMAL, NULL));
cl_f->addVersion(new CompiledFunction(NULL, spec, f, EffortLevel::MAXIMAL, NULL));
}
}
......@@ -42,9 +42,11 @@ extern "C" void dumpLLVM(llvm::Value* v) {
v->dump();
}
IRGenState::IRGenState(CompiledFunction* cf, SourceInfo* source_info, std::unique_ptr<PhiAnalysis> phis,
ParamNames* param_names, GCBuilder* gc, llvm::MDNode* func_dbg_info)
: cf(cf),
IRGenState::IRGenState(CLFunction* clfunc, CompiledFunction* cf, SourceInfo* source_info,
std::unique_ptr<PhiAnalysis> phis, ParamNames* param_names, GCBuilder* gc,
llvm::MDNode* func_dbg_info)
: clfunc(clfunc),
cf(cf),
source_info(source_info),
phis(std::move(phis)),
param_names(param_names),
......@@ -402,8 +404,6 @@ public:
llvm::Value* createIC(const ICSetupInfo* pp, void* func_addr, const std::vector<llvm::Value*>& args,
UnwindInfo unw_info) override {
assert(irstate->getEffortLevel() != EffortLevel::INTERPRETED);
std::vector<llvm::Value*> stackmap_args;
llvm::CallSite rtn
......@@ -493,7 +493,7 @@ private:
assert(ast);
EffortLevel effort = irstate->getEffortLevel();
bool record_types = (effort != EffortLevel::INTERPRETED && effort != EffortLevel::MAXIMAL);
bool record_types = effort != EffortLevel::MAXIMAL;
TypeRecorder* type_recorder;
if (record_types) {
......@@ -531,10 +531,7 @@ private:
emitter.getBuilder()->SetInsertPoint(curblock);
llvm::Value* v = emitter.createCall2(UnwindInfo(current_statement, NULL), g.funcs.deopt,
embedRelocatablePtr(node, g.llvm_aststmt_type_ptr), node_value);
if (irstate->getReturnType() == VOID)
emitter.getBuilder()->CreateRetVoid();
else
emitter.getBuilder()->CreateRet(v);
emitter.getBuilder()->CreateRet(v);
curblock = success_bb;
emitter.getBuilder()->SetInsertPoint(curblock);
......@@ -594,38 +591,29 @@ private:
llvm::Value* cxaexc_pointer = emitter.getBuilder()->CreateExtractValue(landing_pad, { 0 });
if (irstate->getEffortLevel() != EffortLevel::INTERPRETED) {
llvm::Function* std_module_catch = g.stdlib_module->getFunction("__cxa_begin_catch");
auto begin_catch_func = g.cur_module->getOrInsertFunction(std_module_catch->getName(),
std_module_catch->getFunctionType());
assert(begin_catch_func);
llvm::Value* excinfo_pointer = emitter.getBuilder()->CreateCall(begin_catch_func, cxaexc_pointer);
llvm::Value* excinfo_pointer_casted
= emitter.getBuilder()->CreateBitCast(excinfo_pointer, g.llvm_excinfo_type->getPointerTo());
auto* builder = emitter.getBuilder();
llvm::Value* exc_type
= builder->CreateLoad(builder->CreateConstInBoundsGEP2_32(excinfo_pointer_casted, 0, 0));
llvm::Value* exc_value
= builder->CreateLoad(builder->CreateConstInBoundsGEP2_32(excinfo_pointer_casted, 0, 1));
llvm::Value* exc_traceback
= builder->CreateLoad(builder->CreateConstInBoundsGEP2_32(excinfo_pointer_casted, 0, 2));
assert(exc_type->getType() == g.llvm_value_type_ptr);
assert(exc_value->getType() == g.llvm_value_type_ptr);
assert(exc_traceback->getType() == g.llvm_value_type_ptr);
return makeTuple({ new ConcreteCompilerVariable(UNKNOWN, exc_type, true),
new ConcreteCompilerVariable(UNKNOWN, exc_value, true),
new ConcreteCompilerVariable(UNKNOWN, exc_traceback, true) });
} else {
// TODO This doesn't get hit, right?
abort();
llvm::Function* std_module_catch = g.stdlib_module->getFunction("__cxa_begin_catch");
auto begin_catch_func = g.cur_module->getOrInsertFunction(std_module_catch->getName(),
std_module_catch->getFunctionType());
assert(begin_catch_func);
// The interpreter can't really support the full C++ exception handling model since it's
// itself written in C++. Let's make it easier for the interpreter and use a simpler interface:
llvm::Value* exc_obj = emitter.getBuilder()->CreateBitCast(cxaexc_pointer, g.llvm_value_type_ptr);
}
llvm::Value* excinfo_pointer = emitter.getBuilder()->CreateCall(begin_catch_func, cxaexc_pointer);
llvm::Value* excinfo_pointer_casted
= emitter.getBuilder()->CreateBitCast(excinfo_pointer, g.llvm_excinfo_type->getPointerTo());
auto* builder = emitter.getBuilder();
llvm::Value* exc_type
= builder->CreateLoad(builder->CreateConstInBoundsGEP2_32(excinfo_pointer_casted, 0, 0));
llvm::Value* exc_value
= builder->CreateLoad(builder->CreateConstInBoundsGEP2_32(excinfo_pointer_casted, 0, 1));
llvm::Value* exc_traceback
= builder->CreateLoad(builder->CreateConstInBoundsGEP2_32(excinfo_pointer_casted, 0, 2));
assert(exc_type->getType() == g.llvm_value_type_ptr);
assert(exc_value->getType() == g.llvm_value_type_ptr);
assert(exc_traceback->getType() == g.llvm_value_type_ptr);
return makeTuple({ new ConcreteCompilerVariable(UNKNOWN, exc_type, true),
new ConcreteCompilerVariable(UNKNOWN, exc_value, true),
new ConcreteCompilerVariable(UNKNOWN, exc_traceback, true) });
}
case AST_LangPrimitive::LOCALS: {
return new ConcreteCompilerVariable(UNKNOWN, irstate->getBoxedLocalsVar(), true);
......@@ -986,7 +974,7 @@ private:
if (node->id.s() == "None")
return getNone();
bool do_patchpoint = ENABLE_ICGETGLOBALS && (irstate->getEffortLevel() != EffortLevel::INTERPRETED);
bool do_patchpoint = ENABLE_ICGETGLOBALS;
if (do_patchpoint) {
ICSetupInfo* pp = createGetGlobalIC(getOpInfoForNode(node, unw_info).getTypeRecorder());
......@@ -1657,7 +1645,7 @@ private:
// TODO add a CompilerVariable::setattr, which can (similar to getitem)
// statically-resolve the function if possible, and only fall back to
// patchpoints if it couldn't.
bool do_patchpoint = ENABLE_ICSETITEMS && (irstate->getEffortLevel() != EffortLevel::INTERPRETED);
bool do_patchpoint = ENABLE_ICSETITEMS;
if (do_patchpoint) {
ICSetupInfo* pp = createSetitemIC(getEmptyOpInfo(unw_info).getTypeRecorder());
......@@ -1783,7 +1771,7 @@ private:
tget->decvref(emitter);
slice->decvref(emitter);
bool do_patchpoint = ENABLE_ICDELITEMS && (irstate->getEffortLevel() != EffortLevel::INTERPRETED);
bool do_patchpoint = ENABLE_ICDELITEMS;
if (do_patchpoint) {
ICSetupInfo* pp = createDelitemIC(getEmptyOpInfo(unw_info).getTypeRecorder());
......@@ -1955,12 +1943,6 @@ private:
CompilerVariable* val;
if (node->value == NULL) {
if (irstate->getReturnType() == VOID) {
endBlock(DEAD);
emitter.getBuilder()->CreateRetVoid();
return;
}
val = getNone();
} else {
val = evalExpr(node->value, unw_info);
......@@ -2051,8 +2033,8 @@ private:
// Emitting the actual OSR:
emitter.getBuilder()->SetInsertPoint(onramp);
OSREntryDescriptor* entry = OSREntryDescriptor::create(irstate->getCurFunction(), osr_key);
OSRExit* exit = new OSRExit(irstate->getCurFunction(), entry);
OSREntryDescriptor* entry = OSREntryDescriptor::create(irstate->getCL(), osr_key);
OSRExit* exit = new OSRExit(entry);
llvm::Value* partial_func = emitter.getBuilder()->CreateCall(g.funcs.compilePartialFunc,
embedRelocatablePtr(exit, g.i8->getPointerTo()));
......@@ -2185,10 +2167,7 @@ private:
converted_args[i]->decvref(emitter);
}
if (irstate->getReturnType() == VOID)
emitter.getBuilder()->CreateRetVoid();
else
emitter.getBuilder()->CreateRet(rtn);
emitter.getBuilder()->CreateRet(rtn);
emitter.getBuilder()->SetInsertPoint(starting_block);
}
......
......@@ -54,6 +54,9 @@ extern const std::string FRAME_INFO_PTR_NAME;
// TODO this probably shouldn't be here
class IRGenState {
private:
// Note: due to some not-yet-fixed behavior, cf->clfunc is NULL will only get set to point
// to clfunc at the end of irgen.
CLFunction* clfunc;
CompiledFunction* cf;
SourceInfo* source_info;
std::unique_ptr<PhiAnalysis> phis;
......@@ -69,11 +72,12 @@ private:
public:
IRGenState(CompiledFunction* cf, SourceInfo* source_info, std::unique_ptr<PhiAnalysis> phis,
IRGenState(CLFunction* clfunc, CompiledFunction* cf, SourceInfo* source_info, std::unique_ptr<PhiAnalysis> phis,
ParamNames* param_names, GCBuilder* gc, llvm::MDNode* func_dbg_info);
~IRGenState();
CompiledFunction* getCurFunction() { return cf; }
CLFunction* getCL() { return clfunc; }
llvm::Function* getLLVMFunction() { return cf->func; }
......
......@@ -31,26 +31,25 @@ struct StackMap;
class OSREntryDescriptor {
private:
OSREntryDescriptor(CompiledFunction* from_cf, AST_Jump* backedge) : cf(from_cf), backedge(backedge) {}
OSREntryDescriptor(CLFunction* clfunc, AST_Jump* backedge) : clfunc(clfunc), backedge(backedge) { assert(clfunc); }
public:
CompiledFunction* const cf;
CLFunction* clfunc;
AST_Jump* const backedge;
typedef std::map<InternedString, ConcreteCompilerType*> ArgMap;
ArgMap args;
static OSREntryDescriptor* create(CompiledFunction* from_cf, AST_Jump* backedge) {
return new OSREntryDescriptor(from_cf, backedge);
static OSREntryDescriptor* create(CLFunction* clfunc, AST_Jump* backedge) {
return new OSREntryDescriptor(clfunc, backedge);
}
};
class OSRExit {
private:
public:
CompiledFunction* const parent_cf;
const OSREntryDescriptor* entry;
OSRExit(CompiledFunction* parent_cf, const OSREntryDescriptor* entry) : parent_cf(parent_cf), entry(entry) {}
OSRExit(const OSREntryDescriptor* entry) : entry(entry) {}
};
}
......
......@@ -143,15 +143,6 @@ static std::unordered_set<int> extractLiveOuts(StackMap::Record* r, llvm::Callin
}
void processStackmap(CompiledFunction* cf, StackMap* stackmap) {
// FIXME: this is pretty hacky, that we don't delete the patchpoints here.
// We need them currently for the llvm interpreter.
// Eventually we'll get rid of that and use an AST interpreter, and then we won't need this hack.
if (cf->effort == EffortLevel::INTERPRETED) {
assert(!stackmap);
new_patchpoints.clear();
return;
}
int nrecords = stackmap ? stackmap->records.size() : 0;
assert(cf->location_map == NULL);
......
......@@ -135,10 +135,14 @@ public:
bool hasReturnValue() const { return has_return_value; }
llvm::CallingConv::ID getCallingConvention() const {
// FIXME: we currently have some issues with using PreserveAll (the rewriter currently
// does not completely preserve live outs), so disable it temporarily.
#if 0
// The plan is to switch probably everything over to PreseveAll (and potentially AnyReg),
// but for only switch Getattr so the testing can be localized:
if (type == Getattr || type == Setattr)
return llvm::CallingConv::PreserveAll;
#endif
return llvm::CallingConv::C;
}
......
......@@ -276,6 +276,9 @@ struct PythonFrameId {
class PythonFrameIteratorImpl {
public:
PythonFrameId id;
CLFunction* cl; // always exists
// These only exist if id.type==COMPILED:
CompiledFunction* cf;
// We have to save a copy of the regs since it's very difficult to keep the unw_context_t
// structure valid.
......@@ -284,15 +287,26 @@ public:
PythonFrameIteratorImpl() : regs_valid(0) {}
PythonFrameIteratorImpl(PythonFrameId::FrameType type, uint64_t ip, uint64_t bp, CompiledFunction* cf)
: id(PythonFrameId(type, ip, bp)), cf(cf), regs_valid(0) {}
PythonFrameIteratorImpl(PythonFrameId::FrameType type, uint64_t ip, uint64_t bp, CLFunction* cl,
CompiledFunction* cf)
: id(PythonFrameId(type, ip, bp)), cl(cl), cf(cf), regs_valid(0) {
assert(cl);
assert((type == PythonFrameId::COMPILED) == (cf != NULL));
}
CompiledFunction* getCF() const {
assert(cf);
return cf;
}
CLFunction* getCL() const {
assert(cl);
return cl;
}
uint64_t readLocation(const StackMap::Record::Location& loc) {
assert(id.type == PythonFrameId::COMPILED);
if (loc.type == StackMap::Record::Location::LocationType::Register) {
// TODO: need to make sure we deal with patchpoints appropriately
return getReg(loc.regnum);
......@@ -412,6 +426,11 @@ static bool inGeneratorEntry(unw_word_t ip) {
return ((unw_word_t)generatorEntry < ip && ip <= generator_entry_end);
}
static bool inDeopt(unw_word_t ip) {
static unw_word_t deopt_end = getFunctionEnd((unw_word_t)deopt);
return ((unw_word_t)deopt < ip && ip <= deopt_end);
}
static inline unw_word_t get_cursor_reg(unw_cursor_t* cursor, int reg) {
unw_word_t v;
......@@ -430,18 +449,16 @@ static inline unw_word_t get_cursor_bp(unw_cursor_t* cursor) {
// frame information through the PythonFrameIteratorImpl* info arg.
bool frameIsPythonFrame(unw_word_t ip, unw_word_t bp, unw_cursor_t* cursor, PythonFrameIteratorImpl* info) {
CompiledFunction* cf = getCFForAddress(ip);
CLFunction* cl = cf ? cf->clfunc : NULL;
bool jitted = cf != NULL;
if (!cf) {
if (inASTInterpreterExecuteInner(ip)) {
cf = getCFForInterpretedFrame((void*)bp);
assert(cf);
}
}
bool interpreted = !jitted && inASTInterpreterExecuteInner(ip);
if (interpreted)
cl = getCLForInterpretedFrame((void*)bp);
if (!cf)
if (!jitted && !interpreted)
return false;
*info = PythonFrameIteratorImpl(jitted ? PythonFrameId::COMPILED : PythonFrameId::INTERPRETED, ip, bp, cf);
*info = PythonFrameIteratorImpl(jitted ? PythonFrameId::COMPILED : PythonFrameId::INTERPRETED, ip, bp, cl, cf);
if (jitted) {
// Try getting all the callee-save registers, and save the ones we were able to get.
// Some of them may be inaccessible, I think because they weren't defined by that
......@@ -576,10 +593,10 @@ void throwingException(PythonUnwindSession* unwind) {
static const LineInfo lineInfoForFrame(PythonFrameIteratorImpl* frame_it) {
AST_stmt* current_stmt = frame_it->getCurrentStatement();
auto* cf = frame_it->getCF();
assert(cf);
auto* cl = frame_it->getCL();
assert(cl);
auto source = cf->clfunc->source.get();
auto source = cl->source.get();
return LineInfo(current_stmt->lineno, current_stmt->col_offset, source->fn, source->getName());
}
......@@ -609,12 +626,16 @@ void unwindingThroughFrame(PythonUnwindSession* unwind_session, unw_cursor_t* cu
unw_word_t bp = get_cursor_bp(cursor);
PythonFrameIteratorImpl frame_iter;
if (frameIsPythonFrame(ip, bp, cursor, &frame_iter)) {
if (inDeopt(ip)) {
assert(!unwind_session->shouldSkipFrame());
unwind_session->setShouldSkipNextFrame(true);
} else if (frameIsPythonFrame(ip, bp, cursor, &frame_iter)) {
if (!unwind_session->shouldSkipFrame())
unwind_session->addTraceback(lineInfoForFrame(&frame_iter));
// frame_iter->cf->entry_descriptor will be non-null for OSR frames.
unwind_session->setShouldSkipNextFrame((bool)frame_iter.cf->entry_descriptor);
bool was_osr = (frame_iter.getId().type == PythonFrameId::COMPILED) && (frame_iter.cf->entry_descriptor);
unwind_session->setShouldSkipNextFrame(was_osr);
}
}
......@@ -641,16 +662,21 @@ template <typename Func> void unwindPythonStack(Func func) {
unw_word_t ip = get_cursor_ip(&cursor);
unw_word_t bp = get_cursor_bp(&cursor);
// TODO: this should probably just call unwindingThroughFrame?
bool stop_unwinding = false;
PythonFrameIteratorImpl frame_iter;
if (frameIsPythonFrame(ip, bp, &cursor, &frame_iter)) {
if (inDeopt(ip)) {
assert(!unwind_session->shouldSkipFrame());
unwind_session->setShouldSkipNextFrame(true);
} else if (frameIsPythonFrame(ip, bp, &cursor, &frame_iter)) {
if (!unwind_session->shouldSkipFrame())
stop_unwinding = func(&frame_iter);
// frame_iter->cf->entry_descriptor will be non-null for OSR frames.
unwind_session->setShouldSkipNextFrame((bool)frame_iter.cf->entry_descriptor);
bool was_osr = (frame_iter.getId().type == PythonFrameId::COMPILED) && (frame_iter.cf->entry_descriptor);
unwind_session->setShouldSkipNextFrame(was_osr);
}
if (stop_unwinding)
......@@ -791,11 +817,11 @@ ExcInfo* getFrameExcInfo() {
return cur_exc;
}
CompiledFunction* getTopCompiledFunction() {
CLFunction* getTopPythonFunction() {
auto rtn = getTopPythonFrame();
if (!rtn)
return NULL;
return getTopPythonFrame()->getCF();
return getTopPythonFrame()->getCL();
}
Box* getGlobals() {
......@@ -810,10 +836,10 @@ Box* getGlobalsDict() {
}
BoxedModule* getCurrentModule() {
CompiledFunction* compiledFunction = getTopCompiledFunction();
if (!compiledFunction)
CLFunction* clfunc = getTopPythonFunction();
if (!clfunc)
return NULL;
return compiledFunction->clfunc->source->parent_module;
return clfunc->source->parent_module;
}
PythonFrameIterator getPythonFrame(int depth) {
......@@ -844,11 +870,11 @@ PythonFrameIterator::PythonFrameIterator(std::unique_ptr<PythonFrameIteratorImpl
std::swap(this->impl, impl);
}
// TODO factor getStackLocalsIncludingUserHidden and fastLocalsToBoxedLocals
// TODO factor getDeoptState and fastLocalsToBoxedLocals
// because they are pretty ugly but have a pretty repetitive pattern.
FrameStackState getFrameStackState() {
FrameStackState rtn(NULL, NULL);
DeoptState getDeoptState() {
DeoptState rtn;
bool found = false;
unwindPythonStack([&](PythonFrameIteratorImpl* frame_iter) {
BoxedDict* d;
......@@ -917,7 +943,9 @@ FrameStackState getFrameStackState() {
abort();
}
rtn = FrameStackState(d, frame_iter->getFrameInfo());
rtn.frame_state = FrameStackState(d, frame_iter->getFrameInfo());
rtn.cf = cf;
rtn.current_stmt = frame_iter->getCurrentStatement();
found = true;
return true;
});
......@@ -937,17 +965,18 @@ Box* PythonFrameIterator::fastLocalsToBoxedLocals() {
BoxedClosure* closure;
FrameInfo* frame_info;
CompiledFunction* cf = impl->getCF();
ScopeInfo* scope_info = cf->clfunc->source->getScopeInfo();
CLFunction* clfunc = impl->getCL();
ScopeInfo* scope_info = clfunc->source->getScopeInfo();
if (scope_info->areLocalsFromModule()) {
// TODO we should cache this in frame_info->locals or something so that locals()
// (and globals() too) will always return the same dict
RELEASE_ASSERT(cf->clfunc->source->scoping->areGlobalsFromModule(), "");
return cf->clfunc->source->parent_module->getAttrWrapper();
RELEASE_ASSERT(clfunc->source->scoping->areGlobalsFromModule(), "");
return clfunc->source->parent_module->getAttrWrapper();
}
if (impl->getId().type == PythonFrameId::COMPILED) {
CompiledFunction* cf = impl->getCF();
d = new BoxedDict();
uint64_t ip = impl->getId().ip;
......@@ -1081,24 +1110,18 @@ Box* PythonFrameIterator::fastLocalsToBoxedLocals() {
return frame_info->boxedLocals;
}
ExecutionPoint getExecutionPoint() {
auto frame = getTopPythonFrame();
auto cf = frame->getCF();
auto current_stmt = frame->getCurrentStatement();
return ExecutionPoint({.cf = cf, .current_stmt = current_stmt });
}
std::unique_ptr<ExecutionPoint> PythonFrameIterator::getExecutionPoint() {
assert(impl.get());
auto cf = impl->getCF();
auto stmt = impl->getCurrentStatement();
return std::unique_ptr<ExecutionPoint>(new ExecutionPoint({.cf = cf, .current_stmt = stmt }));
AST_stmt* PythonFrameIterator::getCurrentStatement() {
return impl->getCurrentStatement();
}
CompiledFunction* PythonFrameIterator::getCF() {
return impl->getCF();
}
CLFunction* PythonFrameIterator::getCL() {
return impl->getCL();
}
Box* PythonFrameIterator::getGlobalsDict() {
return impl->getGlobalsDict();
}
......
......@@ -51,11 +51,7 @@ void unwindingThroughFrame(PythonUnwindSession* unwind_session, unw_cursor_t* cu
void exceptionCaughtInInterpreter(LineInfo line_info, ExcInfo* exc_info);
struct ExecutionPoint {
CompiledFunction* cf;
AST_stmt* current_stmt;
};
ExecutionPoint getExecutionPoint();
CLFunction* getTopPythonFunction();
// debugging/stat helper, returns python filename:linenumber, or "unknown:-1" if it fails
std::string getCurrentPythonLine();
......@@ -73,9 +69,10 @@ private:
public:
CompiledFunction* getCF();
CLFunction* getCL();
FrameInfo* getFrameInfo();
bool exists() { return impl.get() != NULL; }
std::unique_ptr<ExecutionPoint> getExecutionPoint();
AST_stmt* getCurrentStatement();
Box* fastLocalsToBoxedLocals();
Box* getGlobalsDict();
......@@ -114,13 +111,19 @@ struct FrameStackState {
// after the frame ends.
FrameInfo* frame_info;
FrameStackState() {}
FrameStackState(BoxedDict* locals, FrameInfo* frame_info) : locals(locals), frame_info(frame_info) {}
};
// Returns all the stack locals, including hidden ones.
FrameStackState getFrameStackState();
CompiledFunction* getTopCompiledFunction();
struct DeoptState {
FrameStackState frame_state;
CompiledFunction* cf;
AST_stmt* current_stmt;
};
DeoptState getDeoptState();
}
#endif
......@@ -2472,6 +2472,8 @@ void CFG::print() {
}
CFG* computeCFG(SourceInfo* source, std::vector<AST_stmt*> body) {
STAT_TIMER(t0, "us_timer_computecfg", 0);
CFG* rtn = new CFG();
ScopingAnalysis* scoping_analysis = source->scoping;
......
......@@ -64,7 +64,6 @@ public:
using gc::GCVisitor;
enum class EffortLevel {
INTERPRETED = 0,
MODERATE = 2,
MAXIMAL = 3,
};
......@@ -74,8 +73,8 @@ template <class V> class ValuedCompilerType;
typedef ValuedCompilerType<llvm::Value*> ConcreteCompilerType;
ConcreteCompilerType* typeFromClass(BoxedClass*);
extern ConcreteCompilerType* INT, *BOXED_INT, *LONG, *FLOAT, *BOXED_FLOAT, *VOID, *UNKNOWN, *BOOL, *STR, *NONE, *LIST,
*SLICE, *MODULE, *DICT, *BOOL, *BOXED_BOOL, *BOXED_TUPLE, *SET, *FROZENSET, *CLOSURE, *GENERATOR, *BOXED_COMPLEX,
extern ConcreteCompilerType* INT, *BOXED_INT, *LONG, *FLOAT, *BOXED_FLOAT, *UNKNOWN, *BOOL, *STR, *NONE, *LIST, *SLICE,
*MODULE, *DICT, *BOOL, *BOXED_BOOL, *BOXED_TUPLE, *SET, *FROZENSET, *CLOSURE, *GENERATOR, *BOXED_COMPLEX,
*FRAME_INFO;
extern CompilerType* UNDEF;
......@@ -229,7 +228,6 @@ public:
llvm::Function* func; // the llvm IR object
FunctionSpecialization* spec;
const OSREntryDescriptor* entry_descriptor;
bool is_interpreted;
union {
Box* (*call)(Box*, Box*, Box*, Box**);
......@@ -246,13 +244,12 @@ public:
int64_t times_called, times_speculation_failed;
ICInvalidator dependent_callsites;
LocationMap* location_map; // only meaningful if this is a compiled frame
LocationMap* location_map;
std::vector<ICInfo*> ics;
std::vector<std::unique_ptr<JitCodeBlock>> code_blocks;
CompiledFunction(llvm::Function* func, FunctionSpecialization* spec, bool is_interpreted, void* code,
EffortLevel effort, const OSREntryDescriptor* entry_descriptor);
CompiledFunction(llvm::Function* func, FunctionSpecialization* spec, void* code, EffortLevel effort,
const OSREntryDescriptor* entry_descriptor);
ConcreteCompilerType* getReturnType();
......@@ -322,6 +319,11 @@ public:
// Please use codeForFunction() to access this:
BoxedCode* code_obj;
// For use by the interpreter/baseline jit:
int times_interpreted;
std::vector<std::unique_ptr<JitCodeBlock>> code_blocks;
ICInvalidator dependent_interp_callsites;
// Functions can provide an "internal" version, which will get called instead
// of the normal dispatch through the functionlist.
// This can be used to implement functions which know how to rewrite themselves,
......@@ -331,22 +333,9 @@ public:
InternalCallable internal_callable = NULL;
CLFunction(int num_args, int num_defaults, bool takes_varargs, bool takes_kwargs,
std::unique_ptr<SourceInfo> source)
: paramspec(num_args, num_defaults, takes_varargs, takes_kwargs),
source(std::move(source)),
param_names(this->source->ast, this->source->getInternedStrings()),
always_use_version(NULL),
code_obj(NULL) {
assert(num_args >= num_defaults);
}
CLFunction(int num_args, int num_defaults, bool takes_varargs, bool takes_kwargs, const ParamNames& param_names)
: paramspec(num_args, num_defaults, takes_varargs, takes_kwargs),
source(nullptr),
param_names(param_names),
always_use_version(NULL),
code_obj(NULL) {
assert(num_args >= num_defaults);
}
std::unique_ptr<SourceInfo> source);
CLFunction(int num_args, int num_defaults, bool takes_varargs, bool takes_kwargs, const ParamNames& param_names);
~CLFunction();
int numReceivedArgs() { return paramspec.totalReceived(); }
......@@ -354,7 +343,7 @@ public:
assert(compiled);
assert((compiled->spec != NULL) + (compiled->entry_descriptor != NULL) == 1);
assert(compiled->clfunc == NULL);
assert(compiled->is_interpreted == (compiled->code == NULL));
assert(compiled->code);
compiled->clfunc = this;
if (compiled->entry_descriptor == NULL) {
......
......@@ -849,7 +849,7 @@ Box* execfile(Box* _fn) {
// Run directly inside the current module:
AST_Module* ast = caching_parse_file(fn->data());
ASSERT(getExecutionPoint().cf->clfunc->source->scoping->areGlobalsFromModule(), "need to pass custom globals in");
ASSERT(getTopPythonFunction()->source->scoping->areGlobalsFromModule(), "need to pass custom globals in");
compileAndRunModule(ast, getCurrentModule());
return None;
......
......@@ -121,8 +121,8 @@ public:
static Box* lineno(Box* obj, void*) {
auto f = static_cast<BoxedFrame*>(obj);
f->update();
std::unique_ptr<ExecutionPoint> fr = f->it.getExecutionPoint();
return boxInt(fr->current_stmt->lineno);
AST_stmt* stmt = f->it.getCurrentStatement();
return boxInt(stmt->lineno);
}
DEFAULT_CLASS(frame_cls);
......@@ -130,11 +130,11 @@ public:
static Box* boxFrame(PythonFrameIterator it) {
FrameInfo* fi = it.getFrameInfo();
if (fi->frame_obj == NULL) {
auto cf = it.getCF();
auto cl = it.getCL();
Box* globals = it.getGlobalsDict();
BoxedFrame* f = fi->frame_obj = new BoxedFrame(std::move(it));
f->_globals = globals;
f->_code = codeForCLFunction(cf->clfunc);
f->_code = codeForCLFunction(cl);
}
return fi->frame_obj;
......
......@@ -162,20 +162,19 @@ extern "C" Box* deopt(AST_expr* expr, Box* value) {
RELEASE_ASSERT(0, "deopt is currently broken...");
FrameStackState frame_state = getFrameStackState();
auto execution_point = getExecutionPoint();
auto deopt_state = getDeoptState();
// Should we only do this selectively?
execution_point.cf->speculationFailed();
deopt_state.cf->speculationFailed();
// Except of exc.type we skip initializing the exc fields inside the JITed code path (small perf improvement) that's
// why we have todo it now if we didn't set an exception (which sets all fields)
if (frame_state.frame_info->exc.type == NULL) {
frame_state.frame_info->exc.traceback = NULL;
frame_state.frame_info->exc.value = NULL;
if (deopt_state.frame_state.frame_info->exc.type == NULL) {
deopt_state.frame_state.frame_info->exc.traceback = NULL;
deopt_state.frame_state.frame_info->exc.value = NULL;
}
return astInterpretFrom(execution_point.cf, expr, execution_point.current_stmt, value, frame_state);
return astInterpretFrom(deopt_state.cf->clfunc, expr, deopt_state.current_stmt, value, deopt_state.frame_state);
}
extern "C" bool softspace(Box* b, bool newval) {
......@@ -2662,16 +2661,12 @@ extern "C" void dumpEx(void* p, int levels) {
printf("Has %ld function versions\n", cl->versions.size());
for (CompiledFunction* cf : cl->versions) {
if (cf->is_interpreted) {
printf("[interpreted]\n");
} else {
bool got_name;
std::string name = g.func_addr_registry.getFuncNameAtAddress(cf->code, true, &got_name);
if (got_name)
printf("%s\n", name.c_str());
else
printf("%p\n", cf->code);
}
bool got_name;
std::string name = g.func_addr_registry.getFuncNameAtAddress(cf->code, true, &got_name);
if (got_name)
printf("%s\n", name.c_str());
else
printf("%p\n", cf->code);
}
}
......@@ -2930,26 +2925,7 @@ static CompiledFunction* pickVersion(CLFunction* f, int num_output_args, Box* oa
abort();
}
EffortLevel new_effort = initialEffort();
// Only the interpreter currently supports non-module-globals:
if (!f->source->scoping->areGlobalsFromModule())
new_effort = EffortLevel::INTERPRETED;
std::vector<ConcreteCompilerType*> arg_types;
for (int i = 0; i < num_output_args; i++) {
if (new_effort == EffortLevel::INTERPRETED) {
arg_types.push_back(UNKNOWN);
} else {
Box* arg = getArg(i, oarg1, oarg2, oarg3, oargs);
assert(arg); // only builtin functions can pass NULL args
arg_types.push_back(typeFromClass(arg->cls));
}
}
FunctionSpecialization* spec = new FunctionSpecialization(UNKNOWN, arg_types);
// this also pushes the new CompiledVersion to the back of the version list:
return compileFunction(f, spec, new_effort, NULL);
return NULL;
}
static llvm::StringRef getFunctionName(CLFunction* f) {
......@@ -3500,7 +3476,7 @@ static Box* callChosenCF(CompiledFunction* chosen_cf, BoxedClosure* closure, Box
// This function exists for the rewriter: astInterpretFunction takes 9 args, but the rewriter
// only supports calling functions with at most 6 since it can currently only pass arguments
// in registers.
static Box* astInterpretHelper(CompiledFunction* f, int num_args, BoxedClosure* closure, BoxedGenerator* generator,
static Box* astInterpretHelper(CLFunction* f, int num_args, BoxedClosure* closure, BoxedGenerator* generator,
Box* globals, Box** _args) {
Box* arg1 = _args[0];
Box* arg2 = _args[1];
......@@ -3514,16 +3490,15 @@ Box* callCLFunc(CLFunction* f, CallRewriteArgs* rewrite_args, int num_output_arg
BoxedGenerator* generator, Box* globals, Box* oarg1, Box* oarg2, Box* oarg3, Box** oargs) {
CompiledFunction* chosen_cf = pickVersion(f, num_output_args, oarg1, oarg2, oarg3, oargs);
assert(chosen_cf->is_interpreted == (chosen_cf->code == NULL));
if (chosen_cf->is_interpreted) {
if (!chosen_cf) {
if (rewrite_args) {
rewrite_args->rewriter->addDependenceOn(chosen_cf->dependent_callsites);
RewriterVar::SmallVector arg_vec;
rewrite_args->rewriter->addDependenceOn(f->dependent_interp_callsites);
// TODO this kind of embedded reference needs to be tracked by the GC somehow?
// Or maybe it's ok, since we've guarded on the function object?
arg_vec.push_back(rewrite_args->rewriter->loadConst((intptr_t)chosen_cf, Location::forArg(0)));
arg_vec.push_back(rewrite_args->rewriter->loadConst((intptr_t)f, Location::forArg(0)));
arg_vec.push_back(rewrite_args->rewriter->loadConst((intptr_t)num_output_args, Location::forArg(1)));
arg_vec.push_back(rewrite_args->rewriter->loadConst((intptr_t)closure, Location::forArg(2)));
arg_vec.push_back(rewrite_args->rewriter->loadConst((intptr_t)generator, Location::forArg(3)));
......@@ -3531,6 +3506,7 @@ Box* callCLFunc(CLFunction* f, CallRewriteArgs* rewrite_args, int num_output_arg
// Hacky workaround: the rewriter can only pass arguments in registers, so use this helper function
// to unpack some of the additional arguments:
// TODO if there's only one arg we could just pass it normally
RewriterVar* arg_array = rewrite_args->rewriter->allocate(4);
arg_vec.push_back(arg_array);
if (num_output_args >= 1)
......@@ -3546,8 +3522,7 @@ Box* callCLFunc(CLFunction* f, CallRewriteArgs* rewrite_args, int num_output_arg
rewrite_args->out_success = true;
}
return astInterpretFunction(chosen_cf, num_output_args, closure, generator, globals, oarg1, oarg2, oarg3,
oargs);
return astInterpretFunction(f, num_output_args, closure, generator, globals, oarg1, oarg2, oarg3, oargs);
}
ASSERT(!globals, "need to update the calling conventions if we want to pass globals");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment