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