Commit caa84b81 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #684 from kmod/tiering2

tiering refactoring
parents 0915db4e a87e2eaf
This diff is collapsed.
...@@ -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; }
}; };
} }
......
This diff is collapsed.
...@@ -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