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);
......
......@@ -56,9 +56,9 @@ IRGenState::IRGenState(FunctionMetadata* md, CompiledFunction* cf, SourceInfo* s
func_dbg_info(func_dbg_info),
scratch_space(NULL),
frame_info(NULL),
frame_info_arg(NULL),
globals(NULL),
vregs(NULL),
stmt(NULL),
scratch_size(0) {
assert(cf->func);
assert(!cf->md); // in this case don't need to pass in sourceinfo
......@@ -164,7 +164,18 @@ template <typename Builder> static llvm::Value* getVRegsGep(Builder& builder, ll
return builder.CreateConstInBoundsGEP2_32(v, 0, 4);
}
llvm::Value* IRGenState::getFrameInfoVar() {
template <typename Builder> static llvm::Value* getStmtGep(Builder& builder, llvm::Value* v) {
static_assert(offsetof(FrameInfo, stmt) == 56, "");
return builder.CreateConstInBoundsGEP2_32(v, 0, 5);
}
template <typename Builder> static llvm::Value* getGlobalsGep(Builder& builder, llvm::Value* v) {
static_assert(offsetof(FrameInfo, globals) == 64, "");
return builder.CreateConstInBoundsGEP2_32(v, 0, 6);
}
void IRGenState::setupFrameInfoVar(llvm::Value* passed_closure, llvm::Value* passed_globals,
llvm::Value* frame_info_arg) {
/*
There is a matrix of possibilities here.
......@@ -182,103 +193,125 @@ llvm::Value* IRGenState::getFrameInfoVar() {
- If the function is NAME-scope, we extract the boxedLocals from the frame_info in order
to set this->boxed_locals.
*/
assert(!frame_info);
llvm::BasicBlock& entry_block = getLLVMFunction()->getEntryBlock();
if (!this->frame_info) {
llvm::BasicBlock& entry_block = getLLVMFunction()->getEntryBlock();
llvm::IRBuilder<true> builder(&entry_block);
if (entry_block.begin() != entry_block.end())
builder.SetInsertPoint(&entry_block, entry_block.getFirstInsertionPt());
if (entry_block.getTerminator())
builder.SetInsertPoint(entry_block.getTerminator());
else
builder.SetInsertPoint(&entry_block);
llvm::IRBuilder<true> builder(&entry_block);
if (frame_info_arg) {
// The OSR case
if (entry_block.begin() != entry_block.end())
builder.SetInsertPoint(&entry_block, entry_block.getFirstInsertionPt());
this->frame_info = frame_info_arg;
if (entry_block.getTerminator())
builder.SetInsertPoint(entry_block.getTerminator());
else
builder.SetInsertPoint(&entry_block);
// use vrags array from the interpreter
vregs = builder.CreateLoad(getVRegsGep(builder, frame_info_arg));
llvm::AllocaInst* al_pointer_to_frame_info
= builder.CreateAlloca(g.llvm_frame_info_type->getPointerTo(), NULL, "frame_info_ptr");
if (getScopeInfo()->usesNameLookup()) {
// load frame_info.boxedLocals
this->boxed_locals = builder.CreateLoad(getBoxedLocalsGep(builder, this->frame_info));
}
if (frame_info_arg) {
assert(!passed_closure);
assert(!passed_globals);
} else {
// The "normal" case
assert(!vregs);
getMD()->calculateNumVRegs();
int num_user_visible_vregs = getMD()->source->cfg->sym_vreg_map_user_visible.size();
if (num_user_visible_vregs > 0) {
auto* vregs_alloca
= builder.CreateAlloca(g.llvm_value_type_ptr, getConstantInt(num_user_visible_vregs), "vregs");
// Clear the vregs array because 0 means undefined valued.
builder.CreateMemSet(vregs_alloca, getConstantInt(0, g.i8),
getConstantInt(num_user_visible_vregs * sizeof(Box*)),
vregs_alloca->getAlignment());
vregs = vregs_alloca;
} else
vregs = getNullPtr(g.llvm_value_type_ptr_ptr);
llvm::AllocaInst* al = builder.CreateAlloca(g.llvm_frame_info_type, NULL, "frame_info");
assert(al->isStaticAlloca());
// frame_info.exc.type = NULL
llvm::Constant* null_value = getNullPtr(g.llvm_value_type_ptr);
llvm::Value* exc_info = getExcinfoGep(builder, al);
builder.CreateStore(
null_value, builder.CreateConstInBoundsGEP2_32(exc_info, 0, offsetof(ExcInfo, type) / sizeof(Box*)));
// frame_info.boxedLocals = NULL
llvm::Value* boxed_locals_gep = getBoxedLocalsGep(builder, al);
builder.CreateStore(getNullPtr(g.llvm_value_type_ptr), boxed_locals_gep);
if (getScopeInfo()->usesNameLookup()) {
// frame_info.boxedLocals = createDict()
// (Since this can call into the GC, we have to initialize it to NULL first as we did above.)
this->boxed_locals = builder.CreateCall(g.funcs.createDict);
builder.CreateStore(this->boxed_locals, boxed_locals_gep);
}
// The OSR case
// frame_info.frame_obj = NULL
static llvm::Type* llvm_frame_obj_type_ptr
= llvm::cast<llvm::StructType>(g.llvm_frame_info_type)->getElementType(2);
builder.CreateStore(getNullPtr(llvm_frame_obj_type_ptr), getFrameObjGep(builder, al));
this->frame_info = frame_info_arg;
// frame_info.passed_closure = NULL
builder.CreateStore(getNullPtr(g.llvm_closure_type_ptr), getPassedClosureGep(builder, al));
// set frame_info.vregs
builder.CreateStore(vregs, getVRegsGep(builder, al));
// use vrags array from the interpreter
vregs = builder.CreateLoad(getVRegsGep(builder, frame_info_arg));
this->globals = builder.CreateLoad(getGlobalsGep(builder, frame_info_arg));
this->frame_info = al;
if (getScopeInfo()->usesNameLookup()) {
// load frame_info.boxedLocals
this->boxed_locals = builder.CreateLoad(getBoxedLocalsGep(builder, this->frame_info));
}
}
return this->frame_info;
} else {
// The "normal" case
assert(!vregs);
getMD()->calculateNumVRegs();
int num_user_visible_vregs = getMD()->source->cfg->sym_vreg_map_user_visible.size();
if (num_user_visible_vregs > 0) {
auto* vregs_alloca
= builder.CreateAlloca(g.llvm_value_type_ptr, getConstantInt(num_user_visible_vregs), "vregs");
// Clear the vregs array because 0 means undefined valued.
builder.CreateMemSet(vregs_alloca, getConstantInt(0, g.i8),
getConstantInt(num_user_visible_vregs * sizeof(Box*)), vregs_alloca->getAlignment());
vregs = vregs_alloca;
} else
vregs = getNullPtr(g.llvm_value_type_ptr_ptr);
llvm::AllocaInst* al = builder.CreateAlloca(g.llvm_frame_info_type, NULL, "frame_info");
assert(al->isStaticAlloca());
// frame_info.exc.type = NULL
llvm::Constant* null_value = getNullPtr(g.llvm_value_type_ptr);
llvm::Value* exc_info = getExcinfoGep(builder, al);
builder.CreateStore(null_value,
builder.CreateConstInBoundsGEP2_32(exc_info, 0, offsetof(ExcInfo, type) / sizeof(Box*)));
// frame_info.boxedLocals = NULL
llvm::Value* boxed_locals_gep = getBoxedLocalsGep(builder, al);
builder.CreateStore(getNullPtr(g.llvm_value_type_ptr), boxed_locals_gep);
if (getScopeInfo()->usesNameLookup()) {
// frame_info.boxedLocals = createDict()
// (Since this can call into the GC, we have to initialize it to NULL first as we did above.)
this->boxed_locals = builder.CreateCall(g.funcs.createDict);
builder.CreateStore(this->boxed_locals, boxed_locals_gep);
}
// frame_info.frame_obj = NULL
static llvm::Type* llvm_frame_obj_type_ptr
= llvm::cast<llvm::StructType>(g.llvm_frame_info_type)->getElementType(2);
builder.CreateStore(getNullPtr(llvm_frame_obj_type_ptr), getFrameObjGep(builder, al));
// set frame_info.passed_closure
builder.CreateStore(passed_closure, getPassedClosureGep(builder, al));
// set frame_info.globals
builder.CreateStore(passed_globals, getGlobalsGep(builder, al));
// set frame_info.vregs
builder.CreateStore(vregs, getVRegsGep(builder, al));
this->frame_info = al;
this->globals = passed_globals;
}
stmt = getStmtGep(builder, frame_info);
builder.CreateStore(this->frame_info, al_pointer_to_frame_info);
// Create stackmap to make a pointer to the frame_info location known
PatchpointInfo* info = PatchpointInfo::create(getCurFunction(), 0, 0, 0);
std::vector<llvm::Value*> args;
args.push_back(getConstantInt(info->getId(), g.i64));
args.push_back(getConstantInt(0, g.i32));
args.push_back(al_pointer_to_frame_info);
info->setNumFrameArgs(1);
info->setIsFrameInfoStackmap();
builder.CreateCall(llvm::Intrinsic::getDeclaration(g.cur_module, llvm::Intrinsic::experimental_stackmap), args);
}
llvm::Value* IRGenState::getFrameInfoVar() {
assert(frame_info);
return frame_info;
}
llvm::Value* IRGenState::getBoxedLocalsVar() {
assert(getScopeInfo()->usesNameLookup());
getFrameInfoVar(); // ensures this->boxed_locals_var is initialized
assert(this->boxed_locals != NULL);
return this->boxed_locals;
}
llvm::Value* IRGenState::getVRegsVar() {
if (!vregs) {
// calling this sets also the vregs member
getFrameInfoVar();
assert(vregs);
}
assert(vregs);
return vregs;
}
llvm::Value* IRGenState::getStmtVar() {
assert(stmt);
return stmt;
}
ScopeInfo* IRGenState::getScopeInfo() {
return getSourceInfo()->getScopeInfo();
}
......@@ -288,18 +321,9 @@ ScopeInfo* IRGenState::getScopeInfoForNode(AST* node) {
return source->scoping->getScopeInfoForNode(node);
}
void IRGenState::setGlobals(llvm::Value* globals) {
assert(!source_info->scoping->areGlobalsFromModule());
assert(!this->globals);
this->globals = globals;
}
llvm::Value* IRGenState::getGlobals() {
if (!globals) {
assert(source_info->scoping->areGlobalsFromModule());
this->globals = embedRelocatablePtr(source_info->parent_module, g.llvm_value_type_ptr);
}
return this->globals;
assert(globals);
return globals;
}
llvm::Value* IRGenState::getGlobalsIfCustom() {
......@@ -464,27 +488,10 @@ public:
}
#endif
if (ENABLE_FRAME_INTROSPECTION) {
llvm::Type* rtn_type = llvm::cast<llvm::FunctionType>(llvm::cast<llvm::PointerType>(callee->getType())
->getElementType())->getReturnType();
llvm::Value* bitcasted = getBuilder()->CreateBitCast(callee, g.i8->getPointerTo());
llvm::CallSite cs = emitPatchpoint(rtn_type, NULL, bitcasted, args, {}, unw_info, target_exception_style);
if (rtn_type == cs->getType()) {
return cs.getInstruction();
} else if (rtn_type == g.i1) {
return getBuilder()->CreateTrunc(cs.getInstruction(), rtn_type);
} else if (llvm::isa<llvm::PointerType>(rtn_type)) {
return getBuilder()->CreateIntToPtr(cs.getInstruction(), rtn_type);
} else {
cs.getInstruction()->getType()->dump();
rtn_type->dump();
RELEASE_ASSERT(0, "don't know how to convert those");
}
} else {
return emitCall(unw_info, callee, args, target_exception_style).getInstruction();
}
llvm::Value* stmt = unw_info.current_stmt ? embedRelocatablePtr(unw_info.current_stmt, g.llvm_aststmt_type_ptr)
: getNullPtr(g.llvm_aststmt_type_ptr);
getBuilder()->CreateStore(stmt, irstate->getStmtVar());
return emitCall(unw_info, callee, args, target_exception_style).getInstruction();
}
llvm::Value* createCall(const UnwindInfo& unw_info, llvm::Value* callee,
......@@ -577,7 +584,6 @@ const std::string CREATED_CLOSURE_NAME = "#created_closure";
const std::string PASSED_CLOSURE_NAME = "#passed_closure";
const std::string PASSED_GENERATOR_NAME = "#passed_generator";
const std::string FRAME_INFO_PTR_NAME = "#frame_info_ptr";
const std::string PASSED_GLOBALS_NAME = "#passed_globals";
bool isIsDefinedName(llvm::StringRef name) {
return startswith(name, "!is_defined_");
......@@ -1131,11 +1137,6 @@ private:
return new ConcreteCompilerVariable(typeFromClass(ellipsis_cls), ellipsis, false);
}
llvm::Constant* embedParentModulePtr() {
BoxedModule* parent_module = irstate->getSourceInfo()->parent_module;
return embedRelocatablePtr(parent_module, g.llvm_value_type_ptr, "cParentModule");
}
ConcreteCompilerVariable* _getGlobal(AST_Name* node, const UnwindInfo& unw_info) {
if (node->id.s() == "None")
return getNone();
......@@ -1778,7 +1779,7 @@ private:
if (vst == ScopeInfo::VarScopeType::GLOBAL) {
if (irstate->getSourceInfo()->scoping->areGlobalsFromModule()) {
auto parent_module = llvm::ConstantExpr::getPointerCast(embedParentModulePtr(), g.llvm_value_type_ptr);
auto parent_module = irstate->getGlobals();
ConcreteCompilerVariable* module = new ConcreteCompilerVariable(MODULE, parent_module, false);
module->setattr(emitter, getEmptyOpInfo(unw_info), name.getBox(), val);
module->decvref(emitter);
......@@ -2209,11 +2210,6 @@ private:
sorted_symbol_table[internString(FRAME_INFO_PTR_NAME)]
= new ConcreteCompilerVariable(FRAME_INFO, irstate->getFrameInfoVar(), true);
if (!irstate->getSourceInfo()->scoping->areGlobalsFromModule()) {
sorted_symbol_table[internString(PASSED_GLOBALS_NAME)]
= new ConcreteCompilerVariable(UNKNOWN, irstate->getGlobals(), true);
}
// For OSR calls, we use the same calling convention as in some other places; namely,
// arg1, arg2, arg3, argarray [nargs is ommitted]
// It would be nice to directly pass all variables as arguments, instead of packing them into
......@@ -2595,13 +2591,6 @@ public:
std::vector<llvm::Value*>& stackmap_args) override {
int initial_args = stackmap_args.size();
stackmap_args.push_back(irstate->getFrameInfoVar());
if (!irstate->getSourceInfo()->scoping->areGlobalsFromModule()) {
stackmap_args.push_back(irstate->getGlobals());
pp->addFrameVar(PASSED_GLOBALS_NAME, UNKNOWN);
}
assert(UNBOXED_INT->llvmType() == g.i64);
if (ENABLE_JIT_OBJECT_CACHE) {
llvm::Value* v;
......@@ -2756,40 +2745,48 @@ public:
auto scope_info = irstate->getScopeInfo();
llvm::Value* passed_closure = NULL;
llvm::Function::arg_iterator AI = irstate->getLLVMFunction()->arg_begin();
llvm::Value* passed_closure = NULL;
llvm::Value* generator = NULL;
llvm::Value* globals = NULL;
if (scope_info->takesClosure()) {
passed_closure = AI;
symbol_table[internString(PASSED_CLOSURE_NAME)]
= new ConcreteCompilerVariable(getPassedClosureType(), AI, true);
++AI;
} else
passed_closure = getNullPtr(g.llvm_closure_type_ptr);
// store the passed_closure inside the frame info so that frame introspection can access it without needing
// a stackmap entry
emitter.getBuilder()->CreateStore(passed_closure,
getPassedClosureGep(*emitter.getBuilder(), irstate->getFrameInfoVar()));
if (irstate->getSourceInfo()->is_generator) {
generator = AI;
++AI;
}
if (scope_info->createsClosure()) {
if (!passed_closure)
passed_closure = getNullPtr(g.llvm_closure_type_ptr);
if (!irstate->getSourceInfo()->scoping->areGlobalsFromModule()) {
globals = AI;
++AI;
} else {
BoxedModule* parent_module = irstate->getSourceInfo()->parent_module;
globals = embedRelocatablePtr(parent_module, g.llvm_value_type_ptr, "cParentModule");
}
irstate->setupFrameInfoVar(passed_closure, globals);
if (scope_info->takesClosure()) {
symbol_table[internString(PASSED_CLOSURE_NAME)]
= new ConcreteCompilerVariable(getPassedClosureType(), passed_closure, true);
}
if (scope_info->createsClosure()) {
llvm::Value* new_closure = emitter.getBuilder()->CreateCall2(
g.funcs.createClosure, passed_closure, getConstantInt(scope_info->getClosureSize(), g.i64));
symbol_table[internString(CREATED_CLOSURE_NAME)]
= new ConcreteCompilerVariable(getCreatedClosureType(), new_closure, true);
}
if (irstate->getSourceInfo()->is_generator) {
symbol_table[internString(PASSED_GENERATOR_NAME)] = new ConcreteCompilerVariable(GENERATOR, AI, true);
++AI;
}
if (!irstate->getSourceInfo()->scoping->areGlobalsFromModule()) {
irstate->setGlobals(AI);
++AI;
}
if (irstate->getSourceInfo()->is_generator)
symbol_table[internString(PASSED_GENERATOR_NAME)]
= new ConcreteCompilerVariable(GENERATOR, generator, true);
std::vector<llvm::Value*> python_parameters;
for (int i = 0; i < arg_types.size(); i++) {
......
......@@ -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