Commit 67360572 authored by Marius Wachtler's avatar Marius Wachtler

Don't generate patchpoints for calls to fixed functions which don't need patching

Previously we generated patchpoints for every call because the callee could do a frame introspection
and we could not retrieve the frame info without the additional patchpoint informations.

This change moves all required information inside the FrameInfo.
Because the FrameInfo does not have a fixed offset (different num of stack args and OSR functions reuse the frame info from the interpreter),
we generate at function entry a stack variable which points to the frame_info and than we emit a stackmap intrinsic
in order to know which basepointer relative address it has.
The current statement inside the FrameInfo gets only updated on direct calls - patchpoints still attach it directly instead of updating the memory.
Because always updating the variable is a small slowdown.

This allows us todo inlining of trivial call sites at the llvm IR level.
parent ff657c1f
......@@ -136,23 +136,19 @@ private:
// this variables are used by the baseline JIT, make sure they have an offset < 0x80 so we can use shorter
// instructions
CFGBlock* next_block, *current_block;
AST_stmt* current_inst;
FrameInfo frame_info;
FunctionMetadata* md;
SourceInfo* source_info;
ScopeInfo* scope_info;
PhiAnalysis* phis;
Box** vregs;
ExcInfo last_exception;
BoxedClosure* created_closure;
BoxedGenerator* generator;
unsigned edgecount;
FrameInfo frame_info;
BoxedModule* parent_module;
// This is either a module or a dict
Box* globals;
std::unique_ptr<JitFragmentWriter> jit;
bool should_jit;
......@@ -163,13 +159,15 @@ public:
}
AST_stmt* getCurrentStatement() {
assert(current_inst);
return current_inst;
assert(frame_info.stmt);
return frame_info.stmt;
}
void setCurrentStatement(AST_stmt* stmt) { frame_info.stmt = stmt; }
Box* getGlobals() {
assert(globals);
return globals;
assert(frame_info.globals);
return frame_info.globals;
}
FunctionMetadata* getMD() { return md; }
......@@ -224,12 +222,12 @@ void ASTInterpreter::setFrameInfo(const FrameInfo* frame_info) {
void ASTInterpreter::setGlobals(Box* globals) {
assert(gc::isValidGCObject(globals));
this->globals = globals;
this->frame_info.globals = globals;
}
ASTInterpreter::ASTInterpreter(FunctionMetadata* md, Box** vregs)
: current_block(0),
current_inst(0),
frame_info(ExcInfo(NULL, NULL, NULL)),
md(md),
source_info(md->source.get()),
scope_info(0),
......@@ -239,9 +237,7 @@ ASTInterpreter::ASTInterpreter(FunctionMetadata* md, Box** vregs)
created_closure(0),
generator(0),
edgecount(0),
frame_info(ExcInfo(NULL, NULL, NULL)),
parent_module(source_info->parent_module),
globals(0),
should_jit(false) {
scope_info = source_info->getScopeInfo();
......@@ -352,9 +348,9 @@ Box* ASTInterpreter::executeInner(ASTInterpreter& interpreter, CFGBlock* start_b
}
// Important that this happens after RegisterHelper:
interpreter.current_inst = start_at;
interpreter.setCurrentStatement(start_at);
threading::allowGLReadPreemption();
interpreter.current_inst = NULL;
interpreter.setCurrentStatement(NULL);
if (!from_start) {
interpreter.current_block = start_block;
......@@ -366,7 +362,7 @@ Box* ASTInterpreter::executeInner(ASTInterpreter& interpreter, CFGBlock* start_b
started = true;
}
interpreter.current_inst = s;
interpreter.setCurrentStatement(s);
v = interpreter.visit_stmt(s);
}
} else {
......@@ -396,7 +392,7 @@ Box* ASTInterpreter::executeInner(ASTInterpreter& interpreter, CFGBlock* start_b
}
for (AST_stmt* s : interpreter.current_block->body) {
interpreter.current_inst = s;
interpreter.setCurrentStatement(s);
if (interpreter.jit)
interpreter.jit->emitSetCurrentInst(s);
v = interpreter.visit_stmt(s);
......@@ -432,8 +428,8 @@ void ASTInterpreter::doStore(AST_Name* node, Value value) {
ScopeInfo::VarScopeType vst = node->lookup_type;
if (vst == ScopeInfo::VarScopeType::GLOBAL) {
if (jit)
jit->emitSetGlobal(globals, name.getBox(), value);
setGlobal(globals, name.getBox(), value.o);
jit->emitSetGlobal(frame_info.globals, name.getBox(), value);
setGlobal(frame_info.globals, name.getBox(), value.o);
} else if (vst == ScopeInfo::VarScopeType::NAME) {
if (jit)
jit->emitSetItemName(name.getBox(), value);
......@@ -719,9 +715,6 @@ Box* ASTInterpreter::doOSR(AST_Jump* node) {
if (created_closure)
sorted_symbol_table[source_info->getInternedStrings().get(CREATED_CLOSURE_NAME)] = created_closure;
if (!source_info->scoping->areGlobalsFromModule())
sorted_symbol_table[source_info->getInternedStrings().get(PASSED_GLOBALS_NAME)] = globals;
sorted_symbol_table[source_info->getInternedStrings().get(FRAME_INFO_PTR_NAME)] = (Box*)&frame_info;
if (found_entry == nullptr) {
......@@ -849,7 +842,7 @@ Value ASTInterpreter::visit_langPrimitive(AST_LangPrimitive* node) {
"import * not supported in functions");
Value module = visit_expr(node->args[0]);
v = Value(importStar(module.o, globals), jit ? jit->emitImportStar(module) : NULL);
v = Value(importStar(module.o, frame_info.globals), jit ? jit->emitImportStar(module) : NULL);
} else if (node->opcode == AST_LangPrimitive::NONE) {
v = getNone();
} else if (node->opcode == AST_LangPrimitive::LANDINGPAD) {
......@@ -1037,9 +1030,9 @@ Value ASTInterpreter::createFunction(AST* node, AST_arguments* args, const std::
Box* passed_globals = NULL;
RewriterVar* passed_globals_var = NULL;
if (!getMD()->source->scoping->areGlobalsFromModule()) {
passed_globals = globals;
passed_globals = frame_info.globals;
if (jit)
passed_globals_var = jit->getInterp()->getAttr(offsetof(ASTInterpreter, globals));
passed_globals_var = jit->getInterp()->getAttr(offsetof(ASTInterpreter, frame_info.globals));
}
Value rtn;
......@@ -1103,7 +1096,7 @@ Value ASTInterpreter::visit_makeClass(AST_MakeClass* mkclass) {
Box* passed_globals = NULL;
if (!getMD()->source->scoping->areGlobalsFromModule())
passed_globals = globals;
passed_globals = frame_info.globals;
Box* attrDict
= runtimeCall(createFunctionFromMetadata(md, closure, passed_globals, {}), ArgPassSpec(0), 0, 0, 0, 0, 0);
......@@ -1150,7 +1143,7 @@ Value ASTInterpreter::visit_assert(AST_Assert* node) {
#endif
static BoxedString* AssertionError_str = internStringImmortal("AssertionError");
Box* assertion_type = getGlobal(globals, AssertionError_str);
Box* assertion_type = getGlobal(frame_info.globals, AssertionError_str);
assertFail(assertion_type, node->msg ? visit_expr(node->msg).o : 0);
return Value();
......@@ -1194,7 +1187,7 @@ Value ASTInterpreter::visit_delete(AST_Delete* node) {
if (vst == ScopeInfo::VarScopeType::GLOBAL) {
if (jit)
jit->emitDelGlobal(target->id.getBox());
delGlobal(globals, target->id.getBox());
delGlobal(frame_info.globals, target->id.getBox());
continue;
} else if (vst == ScopeInfo::VarScopeType::NAME) {
if (jit)
......@@ -1489,9 +1482,9 @@ Value ASTInterpreter::visit_name(AST_Name* node) {
case ScopeInfo::VarScopeType::GLOBAL: {
Value v;
if (jit)
v.var = jit->emitGetGlobal(globals, node->id.getBox());
v.var = jit->emitGetGlobal(frame_info.globals, node->id.getBox());
v.o = getGlobal(globals, node->id.getBox());
v.o = getGlobal(frame_info.globals, node->id.getBox());
return v;
}
case ScopeInfo::VarScopeType::DEREF: {
......@@ -1529,7 +1522,7 @@ Value ASTInterpreter::visit_name(AST_Name* node) {
Value v;
if (jit)
v.var = jit->emitGetBoxedLocal(node->id.getBox());
v.o = boxedLocalsGet(frame_info.boxedLocals, node->id.getBox(), globals);
v.o = boxedLocalsGet(frame_info.boxedLocals, node->id.getBox(), frame_info.globals);
assert(gc::isValidGCObject(v.o));
return v;
}
......@@ -1590,7 +1583,7 @@ int ASTInterpreterJitInterface::getCurrentBlockOffset() {
}
int ASTInterpreterJitInterface::getCurrentInstOffset() {
return offsetof(ASTInterpreter, current_inst);
return offsetof(ASTInterpreter, frame_info.stmt);
}
int ASTInterpreterJitInterface::getGeneratorOffset() {
......@@ -1598,7 +1591,7 @@ int ASTInterpreterJitInterface::getGeneratorOffset() {
}
int ASTInterpreterJitInterface::getGlobalsOffset() {
return offsetof(ASTInterpreter, globals);
return offsetof(ASTInterpreter, frame_info.globals);
}
void ASTInterpreterJitInterface::delNameHelper(void* _interpreter, InternedString name) {
......@@ -1855,9 +1848,6 @@ static Box* astInterpretDeoptInner(FunctionMetadata* md, AST_expr* after_expr, A
interpreter.setPassedClosure(p.second);
} else if (name == CREATED_CLOSURE_NAME) {
interpreter.setCreatedClosure(p.second);
} else if (name == PASSED_GLOBALS_NAME) {
assert(!source_info->scoping->areGlobalsFromModule());
interpreter.setGlobals(p.second);
} else {
InternedString interned = md->source->getInternedStrings().get(name);
interpreter.addSymbol(interned, p.second, false);
......@@ -1937,18 +1927,6 @@ static ASTInterpreter* getInterpreterFromFramePtr(void* frame_ptr) {
return *ptr;
}
AST_stmt* getCurrentStatementForInterpretedFrame(void* frame_ptr) {
ASTInterpreter* interpreter = getInterpreterFromFramePtr(frame_ptr);
assert(interpreter);
return interpreter->getCurrentStatement();
}
Box* getGlobalsForInterpretedFrame(void* frame_ptr) {
ASTInterpreter* interpreter = getInterpreterFromFramePtr(frame_ptr);
assert(interpreter);
return interpreter->getGlobals();
}
FunctionMetadata* getMDForInterpretedFrame(void* frame_ptr) {
ASTInterpreter* interpreter = getInterpreterFromFramePtr(frame_ptr);
assert(interpreter);
......@@ -1961,12 +1939,6 @@ FrameInfo* getFrameInfoForInterpretedFrame(void* frame_ptr) {
return interpreter->getFrameInfo();
}
Box** getVRegsForInterpretedFrame(void* frame_ptr) {
ASTInterpreter* interpreter = getInterpreterFromFramePtr(frame_ptr);
assert(interpreter);
return interpreter->getVRegs();
}
BoxedDict* localsForInterpretedFrame(Box** vregs, CFG* cfg) {
BoxedDict* rtn = new BoxedDict();
for (auto& l : cfg->sym_vreg_map_user_visible) {
......
......@@ -76,13 +76,10 @@ Box* astInterpretFunctionEval(FunctionMetadata* cf, Box* globals, Box* boxedLoca
Box* astInterpretDeopt(FunctionMetadata* cf, AST_expr* after_expr, AST_stmt* enclosing_stmt, Box* expr_val,
FrameStackState frame_state);
AST_stmt* getCurrentStatementForInterpretedFrame(void* frame_ptr);
Box* getGlobalsForInterpretedFrame(void* frame_ptr);
FunctionMetadata* getMDForInterpretedFrame(void* frame_ptr);
struct FrameInfo;
FrameInfo* getFrameInfoForInterpretedFrame(void* frame_ptr);
Box** getVRegsForInterpretedFrame(void* frame_ptr);
BoxedDict* localsForInterpretedFrame(Box** vregs, CFG* cfg);
BoxedDict* localsForInterpretedFrame(void* frame_ptr);
......
......@@ -369,6 +369,8 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
llvm_entry_blocks[block] = llvm::BasicBlock::Create(g.context, buf, irstate->getLLVMFunction());
}
llvm::Value* osr_frame_info_arg = NULL;
// the function entry block, where we add the type guards [no guards anymore]
llvm::BasicBlock* osr_entry_block = NULL;
llvm::BasicBlock* osr_unbox_block_end = NULL; // the block after type guards where we up/down-convert things
......@@ -438,17 +440,11 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
if (from_arg->getType() == g.llvm_frame_info_type->getPointerTo()) {
assert(p.first.s() == FRAME_INFO_PTR_NAME);
irstate->setFrameInfoArgument(from_arg);
osr_frame_info_arg = from_arg;
// Don't add the frame info to the symbol table since we will store it separately:
continue;
}
if (p.first.s() == PASSED_GLOBALS_NAME) {
assert(!source->scoping->areGlobalsFromModule());
irstate->setGlobals(from_arg);
continue;
}
ConcreteCompilerType* phi_type;
phi_type = getTypeAtBlockStart(types, p.first, target_block);
......@@ -609,13 +605,13 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
assert(osr_entry_block);
assert(phis);
irstate->setupFrameInfoVarOSR(osr_frame_info_arg);
for (const auto& p : entry_descriptor->args) {
// Don't add the frame info to the symbol table since we will store it separately
// (we manually added it during the calculation of osr_syms):
if (p.first.s() == FRAME_INFO_PTR_NAME)
continue;
if (p.first.s() == PASSED_GLOBALS_NAME)
continue;
ConcreteCompilerType* analyzed_type = getTypeAtBlockStart(types, p.first, block);
......
This diff is collapsed.
......@@ -49,7 +49,6 @@ extern const std::string CREATED_CLOSURE_NAME;
extern const std::string PASSED_CLOSURE_NAME;
extern const std::string PASSED_GENERATOR_NAME;
extern const std::string FRAME_INFO_PTR_NAME;
extern const std::string PASSED_GLOBALS_NAME;
// Class that holds state of the current IR generation, that might not be local
......@@ -70,9 +69,9 @@ private:
llvm::AllocaInst* scratch_space;
llvm::Value* frame_info;
llvm::Value* boxed_locals;
llvm::Value* frame_info_arg;
llvm::Value* globals;
llvm::Value* vregs;
llvm::Value* stmt;
int scratch_size;
public:
......@@ -91,10 +90,15 @@ public:
GCBuilder* getGC() { return gc; }
void setupFrameInfoVar(llvm::Value* passed_closure, llvm::Value* passed_globals,
llvm::Value* frame_info_arg = NULL);
void setupFrameInfoVarOSR(llvm::Value* frame_info_arg) { return setupFrameInfoVar(NULL, NULL, frame_info_arg); }
llvm::Value* getScratchSpace(int min_bytes);
llvm::Value* getFrameInfoVar();
llvm::Value* getBoxedLocalsVar();
llvm::Value* getVRegsVar();
llvm::Value* getStmtVar();
ConcreteCompilerType* getReturnType() { return cf->getReturnType(); }
......@@ -110,9 +114,6 @@ public:
ParamNames* getParamNames() { return param_names; }
void setFrameInfoArgument(llvm::Value* v) { frame_info_arg = v; }
void setGlobals(llvm::Value* globals);
// Returns the custom globals, or the module if the globals come from the module.
llvm::Value* getGlobals();
// Returns the custom globals, or null if the globals come from the module.
......
......@@ -80,16 +80,6 @@ void PatchpointInfo::parseLocationMap(StackMap::Record* r, LocationMap* map) {
// printf("parsing pp %ld:\n", reinterpret_cast<int64_t>(this));
StackMap::Record::Location frame_info_location = r->locations[cur_arg];
cur_arg++;
// We could allow the frame_info to exist in a different location for each callsite,
// but in reality it will always live at a fixed stack offset.
if (map->frameInfoFound()) {
assert(frame_info_location == map->frame_info_location);
} else {
map->frame_info_location = frame_info_location;
}
for (FrameVarInfo& frame_var : frame_vars) {
int num_args = frame_var.type->numFrameArgs();
......@@ -165,6 +155,16 @@ void processStackmap(CompiledFunction* cf, StackMap* stackmap) {
PatchpointInfo* pp = new_patchpoints[r->id].first;
assert(pp);
if (pp->isFrameInfoStackmap()) {
assert(r->locations.size() == pp->totalStackmapArgs());
StackMap::Record::Location frame_info_location = r->locations[0];
assert(!cf->location_map->frameInfoFound());
assert(frame_info_location.type == StackMap::Record::Location::Direct);
assert(frame_info_location.regnum == 6 /* must be rbp based */);
cf->location_map->frame_info_location = frame_info_location;
continue;
}
void* slowpath_func = PatchpointInfo::getSlowpathAddr(r->id);
if (VERBOSITY() >= 2) {
printf("Processing pp %ld; [%d, %d)\n", reinterpret_cast<int64_t>(pp), r->offset,
......
......@@ -106,6 +106,7 @@ private:
const ICSetupInfo* icinfo;
int num_ic_stackmap_args;
int num_frame_stackmap_args;
bool is_frame_info_stackmap;
std::vector<FrameVarInfo> frame_vars;
unsigned int id;
......@@ -115,6 +116,7 @@ private:
icinfo(icinfo),
num_ic_stackmap_args(num_ic_stackmap_args),
num_frame_stackmap_args(-1),
is_frame_info_stackmap(false),
id(0) {}
......@@ -129,6 +131,7 @@ public:
int scratchStackmapArg() { return 0; }
int scratchSize() { return 80 + MAX_FRAME_SPILLS * sizeof(void*); }
bool isDeopt() const { return icinfo ? icinfo->isDeopt() : false; }
bool isFrameInfoStackmap() const { return is_frame_info_stackmap; }
int numFrameSpillsSupported() const { return isDeopt() ? MAX_FRAME_SPILLS : 0; }
void addFrameVar(llvm::StringRef name, CompilerType* type);
......@@ -136,8 +139,9 @@ public:
assert(num_frame_stackmap_args == -1);
num_frame_stackmap_args = num_frame_args;
}
void setIsFrameInfoStackmap(bool b = true) { is_frame_info_stackmap = b; }
int icStackmapArgsStart() { return 1; }
int icStackmapArgsStart() { return isFrameInfoStackmap() ? 0 : 1; }
int numICStackmapArgs() { return num_ic_stackmap_args; }
int frameStackmapArgsStart() { return icStackmapArgsStart() + numICStackmapArgs(); }
......
......@@ -344,7 +344,6 @@ public:
assert(cf->location_map);
const LocationMap::LocationTable& table = cf->location_map->names[name];
assert(table.locations.size());
auto entry = table.findEntry(offset);
if (!entry)
......@@ -356,28 +355,17 @@ public:
AST_stmt* getCurrentStatement() {
if (id.type == PythonFrameId::COMPILED) {
auto locations = findLocations("!current_stmt");
RELEASE_ASSERT(locations.size() == 1, "%ld", locations.size());
return reinterpret_cast<AST_stmt*>(readLocation(locations[0]));
} else if (id.type == PythonFrameId::INTERPRETED) {
return getCurrentStatementForInterpretedFrame((void*)id.bp);
if (locations.size() == 1)
return reinterpret_cast<AST_stmt*>(readLocation(locations[0]));
}
abort();
assert(getFrameInfo()->stmt);
return getFrameInfo()->stmt;
}
Box* getGlobals() {
if (id.type == PythonFrameId::COMPILED) {
CompiledFunction* cf = getCF();
if (cf->md->source->scoping->areGlobalsFromModule())
return cf->md->source->parent_module;
auto locations = findLocations(PASSED_GLOBALS_NAME);
assert(locations.size() == 1);
Box* r = (Box*)readLocation(locations[0]);
ASSERT(gc::isValidGCObject(r), "%p", r);
return r;
} else if (id.type == PythonFrameId::INTERPRETED) {
return getGlobalsForInterpretedFrame((void*)id.bp);
}
abort();
Box* r = getFrameInfo()->globals;
ASSERT(gc::isValidGCObject(r), "%p", r);
return r;
}
Box* getGlobalsDict() {
......@@ -395,8 +383,7 @@ public:
CompiledFunction* cf = getCF();
assert(cf->location_map->frameInfoFound());
const auto& frame_info_loc = cf->location_map->frame_info_location;
return reinterpret_cast<FrameInfo*>(readLocation(frame_info_loc));
return *reinterpret_cast<FrameInfo**>(readLocation(frame_info_loc));
} else if (id.type == PythonFrameId::INTERPRETED) {
return getFrameInfoForInterpretedFrame((void*)id.bp);
}
......
......@@ -886,8 +886,14 @@ struct FrameInfo {
BoxedClosure* passed_closure;
Box** vregs;
FrameInfo(ExcInfo exc) : exc(exc), boxedLocals(NULL), frame_obj(0), passed_closure(0), vregs(0) {}
// Current statement
// Caution the llvm tier only updates this information on direct external calls but not for patchpoints.
// This means if a patchpoint "current_stmt" info is available it must be used instead of this field.
AST_stmt* stmt;
// This is either a module or a dict
Box* globals;
FrameInfo(ExcInfo exc) : exc(exc), boxedLocals(NULL), frame_obj(0), passed_closure(0), vregs(0), stmt(0), globals(0) {}
void gcVisit(GCVisitor* visitor);
};
......
......@@ -47,5 +47,9 @@ i64 unboxInt(Box* b) {
return ((BoxedInt*)b)->n;
}
extern "C" bool hasnext(Box* o) {
return o->cls->tpp_hasnext(o);
}
// BoxedInt::BoxedInt(int64_t n) : Box(int_cls), n(n) {}
}
......@@ -82,22 +82,6 @@ Box* listiter_next(Box* s) noexcept {
return rtn;
}
template <ExceptionStyle S> Box* listiterNext(Box* s) noexcept(S == CAPI) {
Box* rtn = listiter_next(s);
if (!rtn) {
if (S == CAPI) {
PyErr_SetObject(StopIteration, None);
return NULL;
} else
raiseExcHelper(StopIteration, "");
}
return rtn;
}
// force instantiation:
template Box* listiterNext<CAPI>(Box*);
template Box* listiterNext<CXX>(Box*);
Box* listReversed(Box* s) {
assert(PyList_Check(s));
BoxedList* self = static_cast<BoxedList*>(s);
......
......@@ -1246,6 +1246,22 @@ extern "C" int PyList_SetSlice(PyObject* a, Py_ssize_t ilow, Py_ssize_t ihigh, P
}
}
template <ExceptionStyle S> Box* listiterNext(Box* s) noexcept(S == CAPI) {
Box* rtn = listiter_next(s);
if (!rtn) {
if (S == CAPI) {
PyErr_SetObject(StopIteration, None);
return NULL;
} else
raiseExcHelper(StopIteration, (const char*)NULL);
}
return rtn;
}
// force instantiation:
template Box* listiterNext<CAPI>(Box*) noexcept;
template Box* listiterNext<CXX>(Box*);
void BoxedListIterator::gcHandler(GCVisitor* v, Box* b) {
Box::gcHandler(v, b);
BoxedListIterator* it = (BoxedListIterator*)b;
......
......@@ -117,10 +117,6 @@ Box* boxStringFromCharPtr(const char* s) {
return boxString(s);
}
extern "C" bool hasnext(Box* o) {
return o->cls->tpp_hasnext(o);
}
extern "C" void dump(void* p) {
dumpEx(p, 0);
}
......
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