Commit 9e42fe36 authored by Travis Hance's avatar Travis Hance

added to BoxedList so it will work for functions inside the exec

parent 9c78c3d4
......@@ -275,9 +275,11 @@ private:
std::vector<std::pair<InternedString, DerefInfo>> allDerefVarsAndInfo;
bool allDerefVarsAndInfoCached;
bool globals_from_module;
public:
ScopeInfoBase(ScopeInfo* parent, ScopingAnalysis::ScopeNameUsage* usage, AST* ast, bool usesNameLookup)
: parent(parent), usage(usage), ast(ast), usesNameLookup_(usesNameLookup), allDerefVarsAndInfoCached(false) {
ScopeInfoBase(ScopeInfo* parent, ScopingAnalysis::ScopeNameUsage* usage, AST* ast, bool usesNameLookup, bool globals_from_module)
: parent(parent), usage(usage), ast(ast), usesNameLookup_(usesNameLookup), allDerefVarsAndInfoCached(false), globals_from_module(globals_from_module) {
assert(usage);
assert(ast);
......@@ -325,7 +327,7 @@ public:
bool usesNameLookup() override { return usesNameLookup_; }
bool areLocalsFromModule() override { return false; }
bool areGlobalsFromModule() override { return true; }
bool areGlobalsFromModule() override { return globals_from_module; }
DerefInfo getDerefInfo(InternedString name) override {
assert(getScopeTypeOfName(name) == VarScopeType::DEREF);
......@@ -816,7 +818,7 @@ void ScopingAnalysis::processNameUsages(ScopingAnalysis::NameUsageMap* usages) {
switch (node->type) {
case AST_TYPE::ClassDef: {
ScopeInfoBase* scopeInfo
= new ScopeInfoBase(parent_info, usage, usage->node, true /* usesNameLookup */);
= new ScopeInfoBase(parent_info, usage, usage->node, true /* usesNameLookup */, globals_from_module);
this->scopes[node] = scopeInfo;
break;
}
......@@ -826,9 +828,9 @@ void ScopingAnalysis::processNameUsages(ScopingAnalysis::NameUsageMap* usages) {
case AST_TYPE::DictComp:
case AST_TYPE::SetComp: {
ScopeInfoBase* scopeInfo = new ScopeInfoBase(parent_info, usage, usage->node,
usage->hasNameForcingSyntax() /* usesNameLookup */);
this->scopes[node] = scopeInfo;
break;
usage->hasNameForcingSyntax() /* usesNameLookup */,
globals_from_module);
this->scopes[node] = scopeInfo; break;
}
default:
RELEASE_ASSERT(0, "%d", usage->node->type);
......@@ -882,16 +884,16 @@ ScopeInfo* ScopingAnalysis::getScopeInfoForNode(AST* node) {
return analyzeSubtree(node);
}
ScopingAnalysis::ScopingAnalysis(AST_Module* m) : parent_module(m), interned_strings(*m->interned_strings.get()) {
ScopingAnalysis::ScopingAnalysis(AST_Module* m) : parent_module(m), interned_strings(*m->interned_strings.get()), globals_from_module(true) {
scopes[m] = new ModuleScopeInfo();
}
ScopingAnalysis::ScopingAnalysis(AST_Expression* e, bool globals_from_module) : interned_strings(*e->interned_strings.get()) {
ScopingAnalysis::ScopingAnalysis(AST_Expression* e, bool globals_from_module) : interned_strings(*e->interned_strings.get()), globals_from_module(globals_from_module) {
// It's an expression, so it can't have a `global` statement
scopes[e] = new EvalExprScopeInfo(globals_from_module);
}
ScopingAnalysis::ScopingAnalysis(AST_Suite* s, bool globals_from_module) : interned_strings(*s->interned_strings.get()) {
ScopingAnalysis::ScopingAnalysis(AST_Suite* s, bool globals_from_module) : interned_strings(*s->interned_strings.get()), globals_from_module(globals_from_module) {
scopes[s] = new EvalExprScopeInfo(s, globals_from_module);
}
}
......@@ -159,6 +159,8 @@ private:
ScopeInfo* analyzeSubtree(AST* node);
void processNameUsages(NameUsageMap* usages);
bool globals_from_module;
public:
// The scope-analysis is done before any CFG-ization is done,
// but many of the queries will be done post-CFG-ization.
......
......@@ -742,7 +742,7 @@ Box* ASTInterpreter::createFunction(AST* node, AST_arguments* args, const std::v
}
assert(closure);
}
return boxCLFunction(cl, closure, is_generator, u.il);
return boxCLFunction(cl, closure, is_generator, globals->cls == dict_cls ? static_cast<BoxedDict*>(globals) : NULL, u.il);
}
Value ASTInterpreter::visit_makeFunction(AST_MakeFunction* mkfn) {
......@@ -778,7 +778,7 @@ Value ASTInterpreter::visit_makeClass(AST_MakeClass* mkclass) {
BoxedClosure* closure = scope_info->takesClosure() ? created_closure : 0;
CLFunction* cl = wrapFunction(node, nullptr, node->body, source_info);
Box* attrDict = runtimeCall(boxCLFunction(cl, closure, false, {}), ArgPassSpec(0), 0, 0, 0, 0, 0);
Box* attrDict = runtimeCall(boxCLFunction(cl, closure, false, globals->cls == dict_cls ? static_cast<BoxedDict*>(globals) : NULL, {}), ArgPassSpec(0), 0, 0, 0, 0, 0);
Box* classobj = createUserClass(&node->name.str(), basesTuple, attrDict);
......@@ -1164,7 +1164,7 @@ Value ASTInterpreter::visit_attribute(AST_Attribute* node) {
const void* interpreter_instr_addr = (void*)&ASTInterpreter::execute;
Box* astInterpretFunction(CompiledFunction* cf, int nargs, Box* closure, Box* generator, Box* arg1, Box* arg2,
Box* astInterpretFunction(CompiledFunction* cf, int nargs, Box* closure, Box* generator, BoxedDict* globals, Box* arg1, Box* arg2,
Box* arg3, Box** args) {
if (unlikely(cf->times_called > REOPT_THRESHOLD_INTERPRETER && ENABLE_REOPT && !FORCE_INTERPRETER)) {
CompiledFunction* optimized = reoptCompiledFuncInternal(cf);
......@@ -1187,8 +1187,12 @@ Box* astInterpretFunction(CompiledFunction* cf, int nargs, Box* closure, Box* ge
interpreter.setBoxedLocals(new BoxedDict());
}
assert(scope_info->areGlobalsFromModule());
interpreter.setGlobals(source_info->parent_module);
assert((!globals) == scope_info->areGlobalsFromModule());
if (globals) {
interpreter.setGlobals(globals);
} else {
interpreter.setGlobals(source_info->parent_module);
}
interpreter.initArguments(nargs, (BoxedClosure*)closure, (BoxedGenerator*)generator, arg1, arg2, arg3, args);
Value v = ASTInterpreter::execute(interpreter);
......
......@@ -33,7 +33,7 @@ struct LineInfo;
extern const void* interpreter_instr_addr;
Box* astInterpretFunction(CompiledFunction* f, int nargs, Box* closure, Box* generator, Box* arg1, Box* arg2, Box* arg3,
Box* astInterpretFunction(CompiledFunction* f, int nargs, Box* closure, Box* generator, BoxedDict* globals, Box* arg1, Box* arg2, Box* arg3,
Box** args);
Box* astInterpretFunctionEval(CompiledFunction* cf, BoxedDict* globals, Box* boxedLocals);
Box* astInterpretFrom(CompiledFunction* cf, AST_expr* after_expr, AST_stmt* enclosing_stmt, Box* expr_val,
......
......@@ -321,7 +321,7 @@ void compileAndRunModule(AST_Module* m, BoxedModule* bm) {
}
if (cf->is_interpreted)
astInterpretFunction(cf, 0, NULL, NULL, NULL, NULL, NULL, NULL);
astInterpretFunction(cf, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
else
((void (*)())cf->code)();
}
......
......@@ -95,7 +95,7 @@ void generatorEntry(BoxedGenerator* g) {
BoxedFunctionBase* func = g->function;
Box** args = g->args ? &g->args->elts[0] : nullptr;
callCLFunc(func->f, nullptr, func->f->numReceivedArgs(), func->closure, g, g->arg1, g->arg2, g->arg3, args);
callCLFunc(func->f, nullptr, func->f->numReceivedArgs(), func->closure, g, func->globals, g->arg1, g->arg2, g->arg3, args);
} catch (ExcInfo e) {
// unhandled exception: propagate the exception to the caller
g->exception = e;
......
......@@ -2667,7 +2667,7 @@ Box* callFunc(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ArgPassSpe
if (!func->isGenerator) {
if (argspec.num_keywords == 0 && !argspec.has_starargs && !argspec.has_kwargs && argspec.num_args == f->num_args
&& !f->takes_varargs && !f->takes_kwargs) {
return callCLFunc(f, rewrite_args, argspec.num_args, closure, NULL, arg1, arg2, arg3, args);
return callCLFunc(f, rewrite_args, argspec.num_args, closure, NULL, func->globals, arg1, arg2, arg3, args);
}
}
slowpath_callfunc_slowpath.log();
......@@ -2924,19 +2924,19 @@ Box* callFunc(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ArgPassSpe
if (func->isGenerator) {
res = createGenerator(func, oarg1, oarg2, oarg3, oargs);
} else {
res = callCLFunc(f, rewrite_args, num_output_args, closure, NULL, oarg1, oarg2, oarg3, oargs);
res = callCLFunc(f, rewrite_args, num_output_args, closure, NULL, func->globals, oarg1, oarg2, oarg3, oargs);
}
return res;
}
Box* callCLFunc(CLFunction* f, CallRewriteArgs* rewrite_args, int num_output_args, BoxedClosure* closure,
BoxedGenerator* generator, Box* oarg1, Box* oarg2, Box* oarg3, Box** oargs) {
BoxedGenerator* generator, BoxedDict* globals, Box* oarg1, Box* oarg2, Box* oarg3, Box** 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->is_interpreted) {
return astInterpretFunction(chosen_cf, num_output_args, closure, generator, oarg1, oarg2, oarg3, oargs);
return astInterpretFunction(chosen_cf, num_output_args, closure, generator, globals, oarg1, oarg2, oarg3, oargs);
}
if (rewrite_args) {
......
......@@ -138,7 +138,7 @@ bool isUserDefined(BoxedClass* cls);
Box* processDescriptor(Box* obj, Box* inst, Box* owner);
Box* callCLFunc(CLFunction* f, CallRewriteArgs* rewrite_args, int num_output_args, BoxedClosure* closure,
BoxedGenerator* generator, Box* oarg1, Box* oarg2, Box* oarg3, Box** oargs);
BoxedGenerator* generator, BoxedDict* globals, Box* oarg1, Box* oarg2, Box* oarg3, Box** oargs);
static const char* objectNewParameterTypeErrorMsg() {
if (PYTHON_VERSION_HEX >= version_hex(2, 7, 4)) {
......
......@@ -310,9 +310,11 @@ BoxedFunction::BoxedFunction(CLFunction* f) : BoxedFunction(f, {}) {
}
BoxedFunction::BoxedFunction(CLFunction* f, std::initializer_list<Box*> defaults, BoxedClosure* closure,
bool isGenerator)
bool isGenerator, BoxedDict* globals)
: BoxedFunctionBase(f, defaults, closure, isGenerator) {
this->globals = globals;
// TODO eventually we want this to assert(f->source), I think, but there are still
// some builtin functions that are BoxedFunctions but really ought to be a type that
// we don't have yet.
......@@ -355,6 +357,9 @@ extern "C" void functionGCHandler(GCVisitor* v, Box* b) {
if (f->closure)
v->visit(f->closure);
if (f->globals)
v->visit(f->globals);
// It's ok for f->defaults to be NULL here even if f->ndefaults isn't,
// since we could be collecting from inside a BoxedFunctionBase constructor
if (f->ndefaults) {
......@@ -412,12 +417,14 @@ extern "C" void moduleGCHandler(GCVisitor* v, Box* b) {
// This mustn't throw; our IR generator generates calls to it without "invoke" even when there are exception handlers /
// finally-blocks in scope.
// TODO: should we use C++11 `noexcept' here?
extern "C" Box* boxCLFunction(CLFunction* f, BoxedClosure* closure, bool isGenerator,
extern "C" Box* boxCLFunction(CLFunction* f, BoxedClosure* closure, bool isGenerator, BoxedDict* globals,
std::initializer_list<Box*> defaults) {
if (closure)
assert(closure->cls == closure_cls);
if (globals)
assert(globals->cls == dict_cls);
return new BoxedFunction(f, defaults, closure, isGenerator);
return new BoxedFunction(f, defaults, closure, isGenerator, globals);
}
extern "C" CLFunction* unboxCLFunction(Box* b) {
......
......@@ -123,7 +123,7 @@ char* getWriteableStringContents(BoxedString* s);
extern "C" void listAppendInternal(Box* self, Box* v);
extern "C" void listAppendArrayInternal(Box* self, Box** v, int nelts);
extern "C" Box* boxCLFunction(CLFunction* f, BoxedClosure* closure, bool isGenerator,
extern "C" Box* boxCLFunction(CLFunction* f, BoxedClosure* closure, bool isGenerator, BoxedDict* globals,
std::initializer_list<Box*> defaults);
extern "C" CLFunction* unboxCLFunction(Box* b);
extern "C" Box* createUserClass(const std::string* name, Box* base, Box* attr_dict);
......@@ -478,7 +478,13 @@ public:
Box** in_weakreflist;
CLFunction* f;
// TODO these should really go in BoxedFunction but it's annoying because they don't get
// initializd until after BoxedFunctionBase's constructor is run which means they could have
// garbage values when the GC is run (BoxedFunctionBase's constructor might call the GC).
// So ick... needs to be fixed.
BoxedClosure* closure;
BoxedDict* globals;
bool isGenerator;
int ndefaults;
......@@ -502,7 +508,7 @@ public:
BoxedFunction(CLFunction* f);
BoxedFunction(CLFunction* f, std::initializer_list<Box*> defaults, BoxedClosure* closure = NULL,
bool isGenerator = false);
bool isGenerator = false, BoxedDict* globals = NULL);
DEFAULT_CLASS(function_cls);
};
......
......@@ -37,3 +37,16 @@ def f():
c = 20
f()
""" in g, {}
print 'Test global access in comprehensions'
g = {'a' : 4, 'b': 5, 'c': 6}
exec """
global a
global b
global c
print [a for i in xrange(1)]
print {b for i in xrange(1)}
print {i : b for i in xrange(1)}
print
""" in 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