Commit 5b0b1fe8 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #882 from kmod/perf3

Support non-module-globals in the llvm tier
parents 7c96b62e 7267c07e
......@@ -287,7 +287,7 @@ endmacro()
# tests testname directory arguments
add_pyston_test(defaults tests --order-by-mtime)
add_pyston_test(old_parser tests -a=-n -a=-x -t50)
add_pyston_test(force_llvm tests -a=-n -a=-x -t50)
if(${CMAKE_BUILD_TYPE} STREQUAL "Release")
add_pyston_test(max_compilation_tier tests -a=-O -a=-x -t50)
endif()
......
d = dict(x=1, y=0)
exec """
def g():
global y
y += x
""" in d
def f():
g = d['g']
for i in xrange(1000000):
g()
g()
g()
g()
g()
g()
g()
g()
g()
g()
d['y'] += i
f()
print d['y']
from collections import namedtuple
NT = namedtuple("NT", "")
def f():
C = NT
for i in xrange(1000000):
C()
C()
C()
C()
C()
C()
C()
C()
C()
C()
f()
......@@ -647,7 +647,7 @@ Value ASTInterpreter::visit_jump(AST_Jump* node) {
}
Box* ASTInterpreter::doOSR(AST_Jump* node) {
bool can_osr = ENABLE_OSR && !FORCE_INTERPRETER && source_info->scoping->areGlobalsFromModule();
bool can_osr = ENABLE_OSR && !FORCE_INTERPRETER;
if (!can_osr)
return NULL;
......@@ -728,6 +728,9 @@ 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) {
......@@ -1721,7 +1724,7 @@ Box* astInterpretFunction(CLFunction* clfunc, int nargs, Box* closure, Box* gene
SourceInfo* source_info = clfunc->source.get();
assert((!globals) == source_info->scoping->areGlobalsFromModule());
bool can_reopt = ENABLE_REOPT && !FORCE_INTERPRETER && (globals == NULL);
bool can_reopt = ENABLE_REOPT && !FORCE_INTERPRETER;
// If the cfg hasn't been computed yet, just conservatively say that it will be a big function.
// It shouldn't matter, since the cfg should only be NULL if this is the first execution of this
......@@ -1729,8 +1732,6 @@ Box* astInterpretFunction(CLFunction* clfunc, int nargs, Box* closure, Box* gene
int num_blocks = source_info->cfg ? source_info->cfg->blocks.size() : 10000;
int threshold = num_blocks <= 20 ? (REOPT_THRESHOLD_BASELINE / 3) : REOPT_THRESHOLD_BASELINE;
if (unlikely(can_reopt && (FORCE_OPTIMIZE || !ENABLE_INTERPRETER || clfunc->times_interpreted > threshold))) {
assert(!globals);
clfunc->times_interpreted = 0;
EffortLevel new_effort = EffortLevel::MODERATE;
......@@ -1756,15 +1757,24 @@ Box* astInterpretFunction(CLFunction* clfunc, int nargs, Box* closure, Box* gene
UNAVOIDABLE_STAT_TIMER(t0, "us_timer_in_jitted_code");
Box* r;
if (closure && generator)
r = optimized->closure_generator_call((BoxedClosure*)closure, (BoxedGenerator*)generator, arg1, arg2, arg3,
args);
else if (closure)
r = optimized->closure_call((BoxedClosure*)closure, arg1, arg2, arg3, args);
else if (generator)
r = optimized->generator_call((BoxedGenerator*)generator, arg1, arg2, arg3, args);
else
Box* maybe_args[3];
int nmaybe_args = 0;
if (closure)
maybe_args[nmaybe_args++] = closure;
if (generator)
maybe_args[nmaybe_args++] = generator;
if (globals)
maybe_args[nmaybe_args++] = globals;
if (nmaybe_args == 0)
r = optimized->call(arg1, arg2, arg3, args);
else if (nmaybe_args == 1)
r = optimized->call1(maybe_args[0], arg1, arg2, arg3, args);
else if (nmaybe_args == 2)
r = optimized->call2(maybe_args[0], maybe_args[1], arg1, arg2, arg3, args);
else {
assert(nmaybe_args == 3);
r = optimized->call3(maybe_args[0], maybe_args[1], maybe_args[2], arg1, arg2, arg3, args);
}
if (optimized->exception_style == CXX)
return r;
......
......@@ -776,7 +776,7 @@ ConcreteCompilerVariable* UnknownType::hasnext(IREmitter& emitter, const OpInfo&
return boolFromI1(emitter, rtn_val);
}
CompilerVariable* makeFunction(IREmitter& emitter, CLFunction* f, CompilerVariable* closure, Box* globals,
CompilerVariable* makeFunction(IREmitter& emitter, CLFunction* f, CompilerVariable* closure, llvm::Value* globals,
const std::vector<ConcreteCompilerVariable*>& defaults) {
// Unlike the CLFunction*, which can be shared between recompilations, the Box* around it
// should be created anew every time the functiondef is encountered
......@@ -805,14 +805,13 @@ CompilerVariable* makeFunction(IREmitter& emitter, CLFunction* f, CompilerVariab
scratch = getNullPtr(g.llvm_value_type_ptr_ptr);
}
assert(globals == NULL);
llvm::Value* globals_v = getNullPtr(g.llvm_value_type_ptr);
assert(globals);
// We know this function call can't throw, so it's safe to use emitter.getBuilder()->CreateCall() rather than
// emitter.createCall().
llvm::Value* boxed = emitter.getBuilder()->CreateCall(
g.funcs.boxCLFunction, std::vector<llvm::Value*>{ embedRelocatablePtr(f, g.llvm_clfunction_type_ptr), closure_v,
globals_v, scratch, getConstantInt(defaults.size(), g.i64) });
globals, scratch, getConstantInt(defaults.size(), g.i64) });
if (convertedClosure)
convertedClosure->decvref(emitter);
......
......@@ -416,7 +416,7 @@ CompilerVariable* makeUnicode(Box*);
#if 0
CompilerVariable* makeUnicode(IREmitter& emitter, llvm::StringRef);
#endif
CompilerVariable* makeFunction(IREmitter& emitter, CLFunction*, CompilerVariable* closure, Box* globals,
CompilerVariable* makeFunction(IREmitter& emitter, CLFunction*, CompilerVariable* closure, llvm::Value* globals,
const std::vector<ConcreteCompilerVariable*>& defaults);
ConcreteCompilerVariable* undefVariable();
CompilerVariable* makeTuple(const std::vector<CompilerVariable*>& elts);
......
......@@ -442,6 +442,12 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
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);
......@@ -607,6 +613,8 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
// (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);
......@@ -1009,6 +1017,9 @@ CompiledFunction* doCompile(CLFunction* clfunc, SourceInfo* source, ParamNames*
if (source->is_generator)
llvm_arg_types.push_back(g.llvm_generator_type_ptr);
if (!source->scoping->areGlobalsFromModule())
llvm_arg_types.push_back(g.llvm_value_type_ptr);
for (int i = 0; i < nargs; i++) {
if (i == 3) {
llvm_arg_types.push_back(g.llvm_value_type_ptr->getPointerTo());
......
......@@ -56,6 +56,7 @@ IRGenState::IRGenState(CLFunction* clfunc, CompiledFunction* cf, SourceInfo* sou
scratch_space(NULL),
frame_info(NULL),
frame_info_arg(NULL),
globals(NULL),
scratch_size(0) {
assert(cf->func);
assert(!cf->clfunc); // in this case don't need to pass in sourceinfo
......@@ -244,6 +245,26 @@ 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;
}
llvm::Value* IRGenState::getGlobalsIfCustom() {
if (source_info->scoping->areGlobalsFromModule())
return getNullPtr(g.llvm_value_type_ptr);
return getGlobals();
}
class IREmitterImpl : public IREmitter {
private:
IRGenState* irstate;
......@@ -352,9 +373,6 @@ public:
// even though we could allocate it in-line; maybe it's infrequently used enough that it's better
// to not have it take up cache space.
RELEASE_ASSERT(irstate->getSourceInfo()->scoping->areGlobalsFromModule(),
"jit doesn't support custom globals yet");
builder->setEmitter(this);
builder->SetInsertPoint(curblock);
}
......@@ -508,6 +526,7 @@ 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_");
......@@ -741,7 +760,7 @@ private:
module->decvref(emitter);
llvm::Value* r = emitter.createCall2(unw_info, g.funcs.importStar, converted_module->getValue(),
embedParentModulePtr());
irstate->getGlobals());
CompilerVariable* v = new ConcreteCompilerVariable(UNKNOWN, r, true);
converted_module->decvref(emitter);
......@@ -1072,14 +1091,14 @@ private:
ICSetupInfo* pp = createGetGlobalIC(getOpInfoForNode(node, unw_info).getTypeRecorder());
std::vector<llvm::Value*> llvm_args;
llvm_args.push_back(embedParentModulePtr());
llvm_args.push_back(irstate->getGlobals());
llvm_args.push_back(embedRelocatablePtr(node->id.getBox(), g.llvm_boxedstring_type_ptr));
llvm::Value* uncasted = emitter.createIC(pp, (void*)pyston::getGlobal, llvm_args, unw_info);
llvm::Value* r = emitter.getBuilder()->CreateIntToPtr(uncasted, g.llvm_value_type_ptr);
return new ConcreteCompilerVariable(UNKNOWN, r, true);
} else {
llvm::Value* r = emitter.createCall2(unw_info, g.funcs.getGlobal, embedParentModulePtr(),
llvm::Value* r = emitter.createCall2(unw_info, g.funcs.getGlobal, irstate->getGlobals(),
embedRelocatablePtr(node->id.getBox(), g.llvm_boxedstring_type_ptr));
return new ConcreteCompilerVariable(UNKNOWN, r, true);
}
......@@ -1147,7 +1166,7 @@ private:
} else if (vst == ScopeInfo::VarScopeType::NAME) {
llvm::Value* boxedLocals = irstate->getBoxedLocalsVar();
llvm::Value* attr = embedRelocatablePtr(node->id.getBox(), g.llvm_boxedstring_type_ptr);
llvm::Value* module = embedParentModulePtr();
llvm::Value* module = irstate->getGlobals();
llvm::Value* r = emitter.createCall3(unw_info, g.funcs.boxedLocalsGet, boxedLocals, attr, module);
return new ConcreteCompilerVariable(UNKNOWN, r, true);
} else {
......@@ -1402,7 +1421,7 @@ private:
// but since the classdef can't create its own closure, shouldn't need to explicitly
// create that scope to pass the closure through.
assert(irstate->getSourceInfo()->scoping->areGlobalsFromModule());
CompilerVariable* func = makeFunction(emitter, cl, created_closure, NULL, {});
CompilerVariable* func = makeFunction(emitter, cl, created_closure, irstate->getGlobalsIfCustom(), {});
CompilerVariable* attr_dict = func->call(emitter, getEmptyOpInfo(unw_info), ArgPassSpec(0), {}, NULL);
......@@ -1465,8 +1484,7 @@ private:
assert(created_closure);
}
assert(irstate->getSourceInfo()->scoping->areGlobalsFromModule());
CompilerVariable* func = makeFunction(emitter, cl, created_closure, NULL, defaults);
CompilerVariable* func = makeFunction(emitter, cl, created_closure, irstate->getGlobalsIfCustom(), defaults);
for (auto d : defaults) {
d->decvref(emitter);
......@@ -1694,11 +1712,18 @@ private:
assert(vst != ScopeInfo::VarScopeType::DEREF);
if (vst == ScopeInfo::VarScopeType::GLOBAL) {
// TODO do something special here so that it knows to only emit a monomorphic inline cache?
auto parent_module = llvm::ConstantExpr::getPointerCast(embedParentModulePtr(), g.llvm_value_type_ptr);
ConcreteCompilerVariable* module = new ConcreteCompilerVariable(MODULE, parent_module, false);
module->setattr(emitter, getEmptyOpInfo(unw_info), name.getBox(), val);
module->decvref(emitter);
if (irstate->getSourceInfo()->scoping->areGlobalsFromModule()) {
auto parent_module = llvm::ConstantExpr::getPointerCast(embedParentModulePtr(), g.llvm_value_type_ptr);
ConcreteCompilerVariable* module = new ConcreteCompilerVariable(MODULE, parent_module, false);
module->setattr(emitter, getEmptyOpInfo(unw_info), name.getBox(), val);
module->decvref(emitter);
} else {
auto converted = val->makeConverted(emitter, val->getBoxType());
emitter.createCall3(unw_info, g.funcs.setGlobal, irstate->getGlobals(),
embedRelocatablePtr(name.getBox(), g.llvm_boxedstring_type_ptr),
converted->getValue());
converted->decvref(emitter);
}
} else if (vst == ScopeInfo::VarScopeType::NAME) {
// TODO inefficient
llvm::Value* boxedLocals = irstate->getBoxedLocalsVar();
......@@ -1825,7 +1850,7 @@ private:
// We could patchpoint this or try to avoid the overhead, but this should only
// happen when the assertion is actually thrown so I don't think it will be necessary.
static BoxedString* AssertionError_str = internStringImmortal("AssertionError");
llvm_args.push_back(emitter.createCall2(unw_info, g.funcs.getGlobal, embedParentModulePtr(),
llvm_args.push_back(emitter.createCall2(unw_info, g.funcs.getGlobal, irstate->getGlobals(),
embedRelocatablePtr(AssertionError_str, g.llvm_boxedstring_type_ptr)));
ConcreteCompilerVariable* converted_msg = NULL;
......@@ -1906,7 +1931,7 @@ private:
ScopeInfo::VarScopeType vst = scope_info->getScopeTypeOfName(target->id);
if (vst == ScopeInfo::VarScopeType::GLOBAL) {
// Can't use delattr since the errors are different:
emitter.createCall2(unw_info, g.funcs.delGlobal, embedParentModulePtr(),
emitter.createCall2(unw_info, g.funcs.delGlobal, irstate->getGlobals(),
embedRelocatablePtr(target->id.getBox(), g.llvm_boxedstring_type_ptr));
return;
}
......@@ -2155,6 +2180,11 @@ 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
......@@ -2535,6 +2565,11 @@ public:
stackmap_args.push_back(irstate->getFrameInfoVar());
if (!irstate->getSourceInfo()->scoping->areGlobalsFromModule()) {
stackmap_args.push_back(irstate->getGlobals());
pp->addFrameVar(PASSED_GLOBALS_NAME, UNKNOWN);
}
assert(INT->llvmType() == g.i64);
if (ENABLE_JIT_OBJECT_CACHE) {
llvm::Value* v;
......@@ -2700,6 +2735,11 @@ public:
++AI;
}
if (!irstate->getSourceInfo()->scoping->areGlobalsFromModule()) {
irstate->setGlobals(AI);
++AI;
}
std::vector<llvm::Value*> python_parameters;
for (int i = 0; i < arg_types.size(); i++) {
assert(AI != irstate->getLLVMFunction()->arg_end());
......
......@@ -49,6 +49,7 @@ 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,6 +71,7 @@ private:
llvm::Value* frame_info;
llvm::Value* boxed_locals;
llvm::Value* frame_info_arg;
llvm::Value* globals;
int scratch_size;
public:
......@@ -107,6 +109,12 @@ 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.
llvm::Value* getGlobalsIfCustom();
};
// turns CFGBlocks into LLVM IR
......
......@@ -209,6 +209,7 @@ void initGlobalFuncs(GlobalState& g) {
GET(delitem);
GET(getGlobal);
GET(delGlobal);
GET(setGlobal);
GET(binop);
GET(compare);
GET(augbinop);
......
......@@ -37,7 +37,8 @@ struct GlobalFuncs {
*createGenerator, *createSet;
llvm::Value* getattr, *getattr_capi, *setattr, *delattr, *delitem, *delGlobal, *nonzero, *binop, *compare,
*augbinop, *unboxedLen, *getitem, *getitem_capi, *getclsattr, *getGlobal, *setitem, *unaryop, *import,
*importFrom, *importStar, *repr, *str, *strOrUnicode, *exceptionMatches, *yield, *getiterHelper, *hasnext;
*importFrom, *importStar, *repr, *str, *strOrUnicode, *exceptionMatches, *yield, *getiterHelper, *hasnext,
*setGlobal;
llvm::Value* unpackIntoArray, *raiseAttributeError, *raiseAttributeErrorStr, *raiseAttributeErrorCapi,
*raiseAttributeErrorStrCapi, *raiseNotIterableError, *raiseIndexErrorStr, *raiseIndexErrorStrCapi,
......
......@@ -90,6 +90,15 @@ public:
llvm::SmallVector<StackMap::Record::Location, 1> locations;
};
llvm::SmallVector<LocationEntry, 2> locations;
const LocationEntry* findEntry(unsigned offset) const {
for (const LocationMap::LocationTable::LocationEntry& e : locations) {
if (e.offset < offset && offset <= e.offset + e.length) {
return &e;
}
}
return NULL;
}
};
llvm::StringMap<LocationTable> names;
......
......@@ -332,28 +332,31 @@ public:
}
}
AST_stmt* getCurrentStatement() {
if (id.type == PythonFrameId::COMPILED) {
CompiledFunction* cf = getCF();
uint64_t ip = getId().ip;
llvm::ArrayRef<StackMap::Record::Location> findLocations(llvm::StringRef name) {
assert(id.type == PythonFrameId::COMPILED);
assert(ip > cf->code_start);
unsigned offset = ip - cf->code_start;
CompiledFunction* cf = getCF();
uint64_t ip = getId().ip;
assert(cf->location_map);
const LocationMap::LocationTable& table = cf->location_map->names["!current_stmt"];
assert(table.locations.size());
// printf("Looking for something at offset %d (total ip: %lx)\n", offset, ip);
for (const LocationMap::LocationTable::LocationEntry& e : table.locations) {
// printf("(%d, %d]\n", e.offset, e.offset + e.length);
if (e.offset < offset && offset <= e.offset + e.length) {
// printf("Found it\n");
assert(e.locations.size() == 1);
return reinterpret_cast<AST_stmt*>(readLocation(e.locations[0]));
}
}
RELEASE_ASSERT(0, "no frame info found at offset 0x%x / ip 0x%lx!", offset, ip);
assert(ip > cf->code_start);
unsigned offset = ip - cf->code_start;
assert(cf->location_map);
const LocationMap::LocationTable& table = cf->location_map->names[name];
assert(table.locations.size());
auto entry = table.findEntry(offset);
if (!entry)
return {};
assert(entry->locations.size());
return entry->locations;
}
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);
}
......@@ -363,8 +366,13 @@ public:
Box* getGlobals() {
if (id.type == PythonFrameId::COMPILED) {
CompiledFunction* cf = getCF();
assert(cf->clfunc->source->scoping->areGlobalsFromModule());
return cf->clfunc->source->parent_module;
if (cf->clfunc->source->scoping->areGlobalsFromModule())
return cf->clfunc->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);
}
......@@ -869,17 +877,14 @@ DeoptState getDeoptState() {
if (!startswith(p.first(), "!is_defined_"))
continue;
for (const LocationMap::LocationTable::LocationEntry& e : p.second.locations) {
if (e.offset < offset && offset <= e.offset + e.length) {
const auto& locs = e.locations;
assert(locs.size() == 1);
uint64_t v = frame_iter->readLocation(locs[0]);
if ((v & 1) == 0)
is_undefined.insert(p.first().substr(12));
auto e = p.second.findEntry(offset);
if (e) {
auto locs = e->locations;
break;
}
assert(locs.size() == 1);
uint64_t v = frame_iter->readLocation(locs[0]);
if ((v & 1) == 0)
is_undefined.insert(p.first().substr(12));
}
}
......@@ -890,22 +895,21 @@ DeoptState getDeoptState() {
if (is_undefined.count(p.first()))
continue;
for (const LocationMap::LocationTable::LocationEntry& e : p.second.locations) {
if (e.offset < offset && offset <= e.offset + e.length) {
const auto& locs = e.locations;
llvm::SmallVector<uint64_t, 1> vals;
// printf("%s: %s\n", p.first().c_str(), e.type->debugName().c_str());
auto e = p.second.findEntry(offset);
if (e) {
auto locs = e->locations;
for (auto& loc : locs) {
vals.push_back(frame_iter->readLocation(loc));
}
llvm::SmallVector<uint64_t, 1> vals;
// printf("%s: %s\n", p.first().c_str(), e.type->debugName().c_str());
Box* v = e.type->deserializeFromFrame(vals);
// printf("%s: (pp id %ld) %p\n", p.first().c_str(), e._debug_pp_id, v);
ASSERT(gc::isValidGCObject(v), "%p", v);
d->d[boxString(p.first())] = v;
for (auto& loc : locs) {
vals.push_back(frame_iter->readLocation(loc));
}
Box* v = e->type->deserializeFromFrame(vals);
// printf("%s: (pp id %ld) %p\n", p.first().c_str(), e._debug_pp_id, v);
ASSERT(gc::isValidGCObject(v), "%p", v);
d->d[boxString(p.first())] = v;
}
}
} else {
......@@ -964,17 +968,14 @@ Box* PythonFrameIterator::fastLocalsToBoxedLocals() {
if (!startswith(p.first(), "!is_defined_"))
continue;
for (const LocationMap::LocationTable::LocationEntry& e : p.second.locations) {
if (e.offset < offset && offset <= e.offset + e.length) {
const auto& locs = e.locations;
assert(locs.size() == 1);
uint64_t v = impl->readLocation(locs[0]);
if ((v & 1) == 0)
is_undefined.insert(p.first().substr(12));
auto e = p.second.findEntry(offset);
if (e) {
const auto& locs = e->locations;
break;
}
assert(locs.size() == 1);
uint64_t v = impl->readLocation(locs[0]);
if ((v & 1) == 0)
is_undefined.insert(p.first().substr(12));
}
}
......@@ -988,46 +989,43 @@ Box* PythonFrameIterator::fastLocalsToBoxedLocals() {
if (is_undefined.count(p.first()))
continue;
for (const LocationMap::LocationTable::LocationEntry& e : p.second.locations) {
if (e.offset < offset && offset <= e.offset + e.length) {
const auto& locs = e.locations;
auto e = p.second.findEntry(offset);
if (e) {
const auto& locs = e->locations;
llvm::SmallVector<uint64_t, 1> vals;
// printf("%s: %s\n", p.first().c_str(), e.type->debugName().c_str());
// printf("%ld locs\n", locs.size());
llvm::SmallVector<uint64_t, 1> vals;
// printf("%s: %s\n", p.first().c_str(), e.type->debugName().c_str());
// printf("%ld locs\n", locs.size());
for (auto& loc : locs) {
auto v = impl->readLocation(loc);
vals.push_back(v);
// printf("%d %d %d: 0x%lx\n", loc.type, loc.regnum, loc.offset, v);
// dump((void*)v);
}
Box* v = e.type->deserializeFromFrame(vals);
// printf("%s: (pp id %ld) %p\n", p.first().c_str(), e._debug_pp_id, v);
assert(gc::isValidGCObject(v));
d->d[boxString(p.first())] = v;
for (auto& loc : locs) {
auto v = impl->readLocation(loc);
vals.push_back(v);
// printf("%d %d %d: 0x%lx\n", loc.type, loc.regnum, loc.offset, v);
// dump((void*)v);
}
Box* v = e->type->deserializeFromFrame(vals);
// printf("%s: (pp id %ld) %p\n", p.first().c_str(), e._debug_pp_id, v);
assert(gc::isValidGCObject(v));
d->d[boxString(p.first())] = v;
}
}
closure = NULL;
if (cf->location_map->names.count(PASSED_CLOSURE_NAME) > 0) {
for (const LocationMap::LocationTable::LocationEntry& e :
cf->location_map->names[PASSED_CLOSURE_NAME].locations) {
if (e.offset < offset && offset <= e.offset + e.length) {
const auto& locs = e.locations;
auto e = cf->location_map->names[PASSED_CLOSURE_NAME].findEntry(offset);
if (e) {
const auto& locs = e->locations;
llvm::SmallVector<uint64_t, 1> vals;
llvm::SmallVector<uint64_t, 1> vals;
for (auto& loc : locs) {
vals.push_back(impl->readLocation(loc));
}
Box* v = e.type->deserializeFromFrame(vals);
assert(gc::isValidGCObject(v));
closure = static_cast<BoxedClosure*>(v);
for (auto& loc : locs) {
vals.push_back(impl->readLocation(loc));
}
Box* v = e->type->deserializeFromFrame(vals);
assert(gc::isValidGCObject(v));
closure = static_cast<BoxedClosure*>(v);
}
}
......
......@@ -267,6 +267,9 @@ public:
Box* (*closure_call)(BoxedClosure*, Box*, Box*, Box*, Box**);
Box* (*closure_generator_call)(BoxedClosure*, BoxedGenerator*, Box*, Box*, Box*, Box**);
Box* (*generator_call)(BoxedGenerator*, Box*, Box*, Box*, Box**);
Box* (*call1)(Box*, Box*, Box*, Box*, Box**);
Box* (*call2)(Box*, Box*, Box*, Box*, Box*, Box**);
Box* (*call3)(Box*, Box*, Box*, Box*, Box*, Box*, Box**);
void* code;
uintptr_t code_start;
};
......
......@@ -87,6 +87,7 @@ void force() {
FORCE(getclsattr);
FORCE(getGlobal);
FORCE(delGlobal);
FORCE(setGlobal);
FORCE(setitem);
FORCE(delitem);
FORCE(unaryop);
......
......@@ -3669,32 +3669,46 @@ Box* callFunc(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ArgPassSpe
}
template <ExceptionStyle S>
static Box* callChosenCF(CompiledFunction* chosen_cf, BoxedClosure* closure, BoxedGenerator* generator, Box* oarg1,
Box* oarg2, Box* oarg3, Box** oargs) noexcept(S == CAPI) {
static Box* callChosenCF(CompiledFunction* chosen_cf, BoxedClosure* closure, BoxedGenerator* generator, Box* globals,
Box* oarg1, Box* oarg2, Box* oarg3, Box** oargs) noexcept(S == CAPI) {
if (S != chosen_cf->exception_style) {
if (S == CAPI) {
try {
return callChosenCF<CXX>(chosen_cf, closure, generator, oarg1, oarg2, oarg3, oargs);
return callChosenCF<CXX>(chosen_cf, closure, generator, globals, oarg1, oarg2, oarg3, oargs);
} catch (ExcInfo e) {
setCAPIException(e);
return NULL;
}
} else {
Box* r = callChosenCF<CAPI>(chosen_cf, closure, generator, oarg1, oarg2, oarg3, oargs);
Box* r = callChosenCF<CAPI>(chosen_cf, closure, generator, globals, oarg1, oarg2, oarg3, oargs);
if (!r)
throwCAPIException();
return r;
}
}
if (closure && generator)
return chosen_cf->closure_generator_call(closure, generator, oarg1, oarg2, oarg3, oargs);
else if (closure)
return chosen_cf->closure_call(closure, oarg1, oarg2, oarg3, oargs);
else if (generator)
return chosen_cf->generator_call(generator, oarg1, oarg2, oarg3, oargs);
else
assert((globals == NULL)
== (!chosen_cf->clfunc->source || chosen_cf->clfunc->source->scoping->areGlobalsFromModule()));
Box* maybe_args[3];
int nmaybe_args = 0;
if (closure)
maybe_args[nmaybe_args++] = closure;
if (generator)
maybe_args[nmaybe_args++] = generator;
if (globals)
maybe_args[nmaybe_args++] = globals;
if (nmaybe_args == 0)
return chosen_cf->call(oarg1, oarg2, oarg3, oargs);
else if (nmaybe_args == 1)
return chosen_cf->call1(maybe_args[0], oarg1, oarg2, oarg3, oargs);
else if (nmaybe_args == 2)
return chosen_cf->call2(maybe_args[0], maybe_args[1], oarg1, oarg2, oarg3, oargs);
else {
assert(nmaybe_args == 3);
return chosen_cf->call3(maybe_args[0], maybe_args[1], maybe_args[2], oarg1, oarg2, oarg3, oargs);
}
}
// This function exists for the rewriter: astInterpretFunction takes 9 args, but the rewriter
......@@ -3786,8 +3800,6 @@ Box* callCLFunc(CLFunction* f, CallRewriteArgs* rewrite_args, int num_output_arg
}
}
ASSERT(!globals, "need to update the calling conventions if we want to pass globals");
if (rewrite_args) {
rewrite_args->rewriter->addDependenceOn(chosen_cf->dependent_callsites);
......@@ -3803,6 +3815,8 @@ Box* callCLFunc(CLFunction* f, CallRewriteArgs* rewrite_args, int num_output_arg
if (closure)
arg_vec.push_back(rewrite_args->rewriter->loadConst((intptr_t)closure, Location::forArg(0)));
if (globals)
arg_vec.push_back(rewrite_args->rewriter->loadConst((intptr_t)globals, Location::forArg(0)));
if (num_output_args >= 1)
arg_vec.push_back(rewrite_args->arg1);
if (num_output_args >= 2)
......@@ -3840,10 +3854,10 @@ Box* callCLFunc(CLFunction* f, CallRewriteArgs* rewrite_args, int num_output_arg
// code and calls that target to builtins.
if (f->source) {
UNAVOIDABLE_STAT_TIMER(t0, "us_timer_in_jitted_code");
r = callChosenCF<S>(chosen_cf, closure, generator, oarg1, oarg2, oarg3, oargs);
r = callChosenCF<S>(chosen_cf, closure, generator, globals, oarg1, oarg2, oarg3, oargs);
} else {
UNAVOIDABLE_STAT_TIMER(t0, "us_timer_in_builtins");
r = callChosenCF<S>(chosen_cf, closure, generator, oarg1, oarg2, oarg3, oargs);
r = callChosenCF<S>(chosen_cf, closure, generator, globals, oarg1, oarg2, oarg3, oargs);
}
if (!r) {
......@@ -5665,7 +5679,7 @@ extern "C" Box* getGlobal(Box* globals, BoxedString* name) {
}
}
} else {
assert(globals->cls == dict_cls);
ASSERT(globals->cls == dict_cls, "%s", globals->cls->tp_name);
BoxedDict* d = static_cast<BoxedDict*>(globals);
rewriter.reset(NULL);
......@@ -5725,7 +5739,7 @@ Box* getFromGlobals(Box* globals, BoxedString* name) {
}
}
void setGlobal(Box* globals, BoxedString* name, Box* value) {
extern "C" void setGlobal(Box* globals, BoxedString* name, Box* value) {
if (globals->cls == attrwrapper_cls) {
globals = unwrapAttrWrapper(globals);
RELEASE_ASSERT(globals->cls == module_cls, "%s", globals->cls->tp_name);
......
......@@ -211,7 +211,7 @@ extern "C" Box* getGlobal(Box* globals, BoxedString* name);
// Checks for the name just in the passed globals object, and returns NULL if it is not found.
// This includes if the globals object defined a custom __getattr__ method that threw an AttributeError.
Box* getFromGlobals(Box* globals, BoxedString* name);
void setGlobal(Box* globals, BoxedString* name, Box* value);
extern "C" void setGlobal(Box* globals, BoxedString* name, Box* value);
extern "C" void delGlobal(Box* globals, BoxedString* name);
extern "C" void boxedLocalsSet(Box* boxedLocals, BoxedString* attr, Box* val);
......
......@@ -199,3 +199,28 @@ print l
exec s
print __doc__
# Create a function that needs all three extra arguments:
# is a generator, takes a closure, and takes custom globals
s = """
def f(x):
def g(a, b, c, d, e):
for i in xrange(start, x):
print a, b, c, d, e
yield i
return g
"""
g = {'start':2}
l = {}
exec s in g, l
for i in xrange(5):
print list(l['f'](5)(1, 2, 3, 4, 5))
d = dict(x=1, y=0)
exec """
def g():
print sorted(globals().items())
""" in d
s = """
def g():
yield x
yield y
"""
g = {'x': 1, 'y': 4}
l = {}
exec s in g, l
print list(l['g']())
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