Commit 6af09380 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Switch uses of getCurrentModule to a new getGlobals()

The callers were assuming that the module represents the globals,
which is not always true.

We can currently fetch globals from the interpreter, but not the jit.
We don't allow custom globals through the jit, so for now we can just
return the module; I think we should be able to support the jit by adding
the globals as a stackmap arg.
parent d48c5f97
...@@ -150,6 +150,11 @@ public: ...@@ -150,6 +150,11 @@ public:
return current_inst; return current_inst;
} }
Box* getGlobals() {
assert(globals);
return globals;
}
CompiledFunction* getCF() { return compiled_func; } CompiledFunction* getCF() { return compiled_func; }
FrameInfo* getFrameInfo() { return &frame_info; } FrameInfo* getFrameInfo() { return &frame_info; }
BoxedClosure* getPassedClosure() { return passed_closure; } BoxedClosure* getPassedClosure() { return passed_closure; }
...@@ -584,9 +589,13 @@ Value ASTInterpreter::visit_langPrimitive(AST_LangPrimitive* node) { ...@@ -584,9 +589,13 @@ Value ASTInterpreter::visit_langPrimitive(AST_LangPrimitive* node) {
assert(node->args.size() == 1); assert(node->args.size() == 1);
assert(node->args[0]->type == AST_TYPE::Name); assert(node->args[0]->type == AST_TYPE::Name);
RELEASE_ASSERT(source_info->ast->type == AST_TYPE::Module, "import * not supported in functions"); RELEASE_ASSERT(source_info->ast->type == AST_TYPE::Module || source_info->ast->type == AST_TYPE::Suite,
"import * not supported in functions");
Value module = visit_expr(node->args[0]); Value module = visit_expr(node->args[0]);
RELEASE_ASSERT(globals == source_info->parent_module,
"'import *' currently not supported with overridden globals");
v = importStar(module.o, source_info->parent_module); v = importStar(module.o, source_info->parent_module);
} else if (node->opcode == AST_LangPrimitive::NONE) { } else if (node->opcode == AST_LangPrimitive::NONE) {
v = None; v = None;
...@@ -1314,6 +1323,12 @@ AST_stmt* getCurrentStatementForInterpretedFrame(void* frame_ptr) { ...@@ -1314,6 +1323,12 @@ AST_stmt* getCurrentStatementForInterpretedFrame(void* frame_ptr) {
return interpreter->getCurrentStatement(); return interpreter->getCurrentStatement();
} }
Box* getGlobalsForInterpretedFrame(void* frame_ptr) {
ASTInterpreter* interpreter = s_interpreterMap[frame_ptr];
assert(interpreter);
return interpreter->getGlobals();
}
CompiledFunction* getCFForInterpretedFrame(void* frame_ptr) { CompiledFunction* getCFForInterpretedFrame(void* frame_ptr) {
ASTInterpreter* interpreter = s_interpreterMap[frame_ptr]; ASTInterpreter* interpreter = s_interpreterMap[frame_ptr];
assert(interpreter); assert(interpreter);
......
...@@ -40,6 +40,7 @@ Box* astInterpretFrom(CompiledFunction* cf, AST_expr* after_expr, AST_stmt* encl ...@@ -40,6 +40,7 @@ Box* astInterpretFrom(CompiledFunction* cf, AST_expr* after_expr, AST_stmt* encl
FrameStackState frame_state); FrameStackState frame_state);
AST_stmt* getCurrentStatementForInterpretedFrame(void* frame_ptr); AST_stmt* getCurrentStatementForInterpretedFrame(void* frame_ptr);
Box* getGlobalsForInterpretedFrame(void* frame_ptr);
CompiledFunction* getCFForInterpretedFrame(void* frame_ptr); CompiledFunction* getCFForInterpretedFrame(void* frame_ptr);
struct FrameInfo; struct FrameInfo;
FrameInfo* getFrameInfoForInterpretedFrame(void* frame_ptr); FrameInfo* getFrameInfoForInterpretedFrame(void* frame_ptr);
......
...@@ -332,6 +332,8 @@ template <typename AST_Type> ...@@ -332,6 +332,8 @@ template <typename AST_Type>
Box* evalOrExec(AST_Type* source, std::vector<AST_stmt*>& body, BoxedModule* bm, BoxedDict* globals, Box* boxedLocals) { Box* evalOrExec(AST_Type* source, std::vector<AST_stmt*>& body, BoxedModule* bm, BoxedDict* globals, Box* boxedLocals) {
CompiledFunction* cf; CompiledFunction* cf;
assert(!globals || globals->cls == dict_cls);
{ // scope for limiting the locked region: { // scope for limiting the locked region:
LOCK_REGION(codegen_rwlock.asWrite()); LOCK_REGION(codegen_rwlock.asWrite());
...@@ -361,6 +363,10 @@ Box* evalOrExec(AST_Type* source, std::vector<AST_stmt*>& body, BoxedModule* bm, ...@@ -361,6 +363,10 @@ Box* evalOrExec(AST_Type* source, std::vector<AST_stmt*>& body, BoxedModule* bm,
Box* eval(Box* boxedCode) { Box* eval(Box* boxedCode) {
Box* boxedLocals = fastLocalsToBoxedLocals(); Box* boxedLocals = fastLocalsToBoxedLocals();
BoxedModule* module = getCurrentModule(); BoxedModule* module = getCurrentModule();
Box* globals = getGlobals();
if (globals == module)
globals = NULL;
// TODO error message if parse fails or if it isn't an expr // TODO error message if parse fails or if it isn't an expr
// TODO should have a cleaner interface that can parse the Expression directly // TODO should have a cleaner interface that can parse the Expression directly
...@@ -378,7 +384,9 @@ Box* eval(Box* boxedCode) { ...@@ -378,7 +384,9 @@ Box* eval(Box* boxedCode) {
stmt->value = parsedExpr->body; stmt->value = parsedExpr->body;
std::vector<AST_stmt*> body = { stmt }; std::vector<AST_stmt*> body = { stmt };
return evalOrExec<AST_Expression>(parsedExpr, body, module, NULL, boxedLocals); assert(!globals || globals->cls == dict_cls);
return evalOrExec<AST_Expression>(parsedExpr, body, module, static_cast<BoxedDict*>(globals), boxedLocals);
} }
Box* exec(Box* boxedCode, Box* globals, Box* locals) { Box* exec(Box* boxedCode, Box* globals, Box* locals) {
...@@ -398,10 +406,22 @@ Box* exec(Box* boxedCode, Box* globals, Box* locals) { ...@@ -398,10 +406,22 @@ Box* exec(Box* boxedCode, Box* globals, Box* locals) {
locals = fastLocalsToBoxedLocals(); locals = fastLocalsToBoxedLocals();
} }
if (globals == NULL)
globals = getGlobals();
BoxedModule* module = getCurrentModule(); BoxedModule* module = getCurrentModule();
if (globals == module)
globals = NULL;
assert(!globals || globals->cls == dict_cls); assert(!globals || globals->cls == dict_cls);
if (globals) {
// From CPython (they set it to be f->f_builtins):
if (PyDict_GetItemString(globals, "__builtins__") == NULL)
PyDict_SetItemString(globals, "__builtins__", builtins_module);
}
// TODO same issues as in `eval` // TODO same issues as in `eval`
RELEASE_ASSERT(boxedCode->cls == str_cls, ""); RELEASE_ASSERT(boxedCode->cls == str_cls, "");
const char* code = static_cast<BoxedString*>(boxedCode)->s.c_str(); const char* code = static_cast<BoxedString*>(boxedCode)->s.c_str();
......
...@@ -300,6 +300,17 @@ public: ...@@ -300,6 +300,17 @@ public:
abort(); abort();
} }
Box* getGlobals() {
if (id.type == PythonFrameId::COMPILED) {
CompiledFunction* cf = getCF();
assert(cf->clfunc->source->scoping->areGlobalsFromModule());
return cf->clfunc->source->parent_module;
} else if (id.type == PythonFrameId::INTERPRETED) {
return getGlobalsForInterpretedFrame((void*)id.bp);
}
abort();
}
FrameInfo* getFrameInfo() { FrameInfo* getFrameInfo() {
if (id.type == PythonFrameId::COMPILED) { if (id.type == PythonFrameId::COMPILED) {
CompiledFunction* cf = getCF(); CompiledFunction* cf = getCF();
...@@ -561,6 +572,21 @@ CompiledFunction* getTopCompiledFunction() { ...@@ -561,6 +572,21 @@ CompiledFunction* getTopCompiledFunction() {
return getTopPythonFrame()->getCF(); return getTopPythonFrame()->getCF();
} }
Box* getGlobals() {
auto it = getTopPythonFrame();
return it->getGlobals();
}
Box* getGlobalsDict() {
Box* globals = getGlobals();
if (!globals)
return NULL;
if (isSubclass(globals->cls, module_cls))
return makeAttrWrapper(globals);
return globals;
}
BoxedModule* getCurrentModule() { BoxedModule* getCurrentModule() {
CompiledFunction* compiledFunction = getTopCompiledFunction(); CompiledFunction* compiledFunction = getTopCompiledFunction();
if (!compiledFunction) if (!compiledFunction)
...@@ -656,7 +682,7 @@ Box* fastLocalsToBoxedLocals() { ...@@ -656,7 +682,7 @@ Box* fastLocalsToBoxedLocals() {
if (scope_info->areLocalsFromModule()) { if (scope_info->areLocalsFromModule()) {
// TODO we should cache this in frame_info->locals or something so that locals() // TODO we should cache this in frame_info->locals or something so that locals()
// (and globals() too) will always return the same dict // (and globals() too) will always return the same dict
return makeAttrWrapper(getCurrentModule()); return getGlobalsDict();
} }
if (frame_iter.getId().type == PythonFrameId::COMPILED) { if (frame_iter.getId().type == PythonFrameId::COMPILED) {
......
...@@ -28,6 +28,8 @@ class BoxedTraceback; ...@@ -28,6 +28,8 @@ class BoxedTraceback;
struct FrameInfo; struct FrameInfo;
BoxedModule* getCurrentModule(); BoxedModule* getCurrentModule();
Box* getGlobals(); // returns either the module or a globals dict
Box* getGlobalsDict(); // always returns a dict-like object
BoxedTraceback* getTraceback(); BoxedTraceback* getTraceback();
......
...@@ -2465,12 +2465,18 @@ CFG* computeCFG(SourceInfo* source, std::vector<AST_stmt*> body) { ...@@ -2465,12 +2465,18 @@ CFG* computeCFG(SourceInfo* source, std::vector<AST_stmt*> body) {
if (source->ast->type == AST_TYPE::ClassDef) { if (source->ast->type == AST_TYPE::ClassDef) {
// A classdef always starts with "__module__ = __name__" // A classdef always starts with "__module__ = __name__"
Box* module_name = source->parent_module->getattr("__name__", NULL);
assert(module_name->cls == str_cls);
AST_Assign* module_assign = new AST_Assign(); AST_Assign* module_assign = new AST_Assign();
module_assign->targets.push_back( module_assign->targets.push_back(
new AST_Name(source->getInternedStrings().get("__module__"), AST_TYPE::Store, source->ast->lineno)); new AST_Name(source->getInternedStrings().get("__module__"), AST_TYPE::Store, source->ast->lineno));
module_assign->value = new AST_Str(static_cast<BoxedString*>(module_name)->s);
if (source->scoping->areGlobalsFromModule()) {
Box* module_name = source->parent_module->getattr("__name__", NULL);
assert(module_name->cls == str_cls);
module_assign->value = new AST_Str(static_cast<BoxedString*>(module_name)->s);
} else {
module_assign->value
= new AST_Name(source->getInternedStrings().get("__name__"), AST_TYPE::Load, source->ast->lineno);
}
module_assign->lineno = 0; module_assign->lineno = 0;
visitor.push_back(module_assign); visitor.push_back(module_assign);
......
...@@ -725,9 +725,8 @@ public: ...@@ -725,9 +725,8 @@ public:
}; };
Box* globals() { Box* globals() {
BoxedModule* m = getCurrentModule();
// TODO is it ok that we don't return a real dict here? // TODO is it ok that we don't return a real dict here?
return makeAttrWrapper(m); return getGlobalsDict();
} }
Box* locals() { Box* locals() {
...@@ -774,6 +773,7 @@ Box* execfile(Box* _fn) { ...@@ -774,6 +773,7 @@ Box* execfile(Box* _fn) {
// Run directly inside the current module: // Run directly inside the current module:
AST_Module* ast = caching_parse_file(fn->s.c_str()); AST_Module* ast = caching_parse_file(fn->s.c_str());
ASSERT(getExecutionPoint().cf->clfunc->source->scoping->areGlobalsFromModule(), "need to pass custom globals in");
compileAndRunModule(ast, getCurrentModule()); compileAndRunModule(ast, getCurrentModule());
return None; return None;
......
...@@ -442,6 +442,7 @@ static bool loadNext(Box* mod, Box* altmod, std::string& name, std::string& buf, ...@@ -442,6 +442,7 @@ static bool loadNext(Box* mod, Box* altmod, std::string& name, std::string& buf,
static void ensureFromlist(Box* module, Box* fromlist, std::string& buf, bool recursive); static void ensureFromlist(Box* module, Box* fromlist, std::string& buf, bool recursive);
Box* importModuleLevel(std::string* name, Box* globals, Box* from_imports, int level) { Box* importModuleLevel(std::string* name, Box* globals, Box* from_imports, int level) {
assert(!globals || globals == None || isSubclass(globals->cls, module_cls));
bool return_first = from_imports == None; bool return_first = from_imports == None;
assert(name); assert(name);
......
...@@ -3917,8 +3917,12 @@ Box* typeNew(Box* _cls, Box* arg1, Box* arg2, Box** _args) { ...@@ -3917,8 +3917,12 @@ Box* typeNew(Box* _cls, Box* arg1, Box* arg2, Box** _args) {
made->setattr(static_cast<BoxedString*>(k)->s, p.second, NULL); made->setattr(static_cast<BoxedString*>(k)->s, p.second, NULL);
} }
if (!made->hasattr("__module__")) if (!made->hasattr("__module__")) {
made->giveAttr("__module__", boxString(getCurrentModule()->name())); Box* gl = getGlobalsDict();
Box* attr = PyDict_GetItemString(gl, "__name__");
if (attr)
made->giveAttr("__module__", attr);
}
if (!made->hasattr("__doc__")) if (!made->hasattr("__doc__"))
made->giveAttr("__doc__", None); made->giveAttr("__doc__", None);
...@@ -4375,6 +4379,10 @@ extern "C" Box* importFrom(Box* _m, const std::string* name) { ...@@ -4375,6 +4379,10 @@ extern "C" Box* importFrom(Box* _m, const std::string* name) {
} }
extern "C" Box* importStar(Box* _from_module, BoxedModule* to_module) { extern "C" Box* importStar(Box* _from_module, BoxedModule* to_module) {
// TODO(kmod): it doesn't seem too bad to update this to take custom globals;
// it looks like mostly a matter of changing the getattr calls to getitem.
RELEASE_ASSERT(getGlobals() == to_module, "importStar doesn't support custom globals yet");
assert(_from_module->cls == module_cls); assert(_from_module->cls == module_cls);
BoxedModule* from_module = static_cast<BoxedModule*>(_from_module); BoxedModule* from_module = static_cast<BoxedModule*>(_from_module);
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "capi/typeobject.h" #include "capi/typeobject.h"
#include "capi/types.h" #include "capi/types.h"
#include "codegen/unwinding.h"
#include "core/options.h" #include "core/options.h"
#include "core/stats.h" #include "core/stats.h"
#include "core/types.h" #include "core/types.h"
...@@ -273,7 +274,7 @@ extern "C" BoxedFunctionBase::BoxedFunctionBase(CLFunction* f) ...@@ -273,7 +274,7 @@ extern "C" BoxedFunctionBase::BoxedFunctionBase(CLFunction* f)
: in_weakreflist(NULL), f(f), closure(NULL), isGenerator(false), ndefaults(0), defaults(NULL), modname(NULL), : in_weakreflist(NULL), f(f), closure(NULL), isGenerator(false), ndefaults(0), defaults(NULL), modname(NULL),
name(NULL), doc(NULL) { name(NULL), doc(NULL) {
if (f->source) { if (f->source) {
this->modname = f->source->parent_module->getattr("__name__", NULL); this->modname = PyDict_GetItemString(getGlobalsDict(), "__name__");
this->doc = f->source->getDocString(); this->doc = f->source->getDocString();
} else { } else {
this->modname = boxStringPtr(&builtinStr); this->modname = boxStringPtr(&builtinStr);
...@@ -296,7 +297,7 @@ extern "C" BoxedFunctionBase::BoxedFunctionBase(CLFunction* f, std::initializer_ ...@@ -296,7 +297,7 @@ extern "C" BoxedFunctionBase::BoxedFunctionBase(CLFunction* f, std::initializer_
} }
if (f->source) { if (f->source) {
this->modname = f->source->parent_module->getattr("__name__", NULL); this->modname = PyDict_GetItemString(getGlobalsDict(), "__name__");
this->doc = f->source->getDocString(); this->doc = f->source->getDocString();
} else { } else {
this->modname = boxStringPtr(&builtinStr); this->modname = boxStringPtr(&builtinStr);
...@@ -676,8 +677,8 @@ extern "C" Box* createUserClass(const std::string* name, Box* _bases, Box* _attr ...@@ -676,8 +677,8 @@ extern "C" Box* createUserClass(const std::string* name, Box* _bases, Box* _attr
// an error, then look up ob_type (aka cls) // an error, then look up ob_type (aka cls)
metaclass = bases->elts[0]->cls; metaclass = bases->elts[0]->cls;
} else { } else {
BoxedModule* m = getCurrentModule(); Box* gl = getGlobalsDict();
metaclass = m->getattr("__metaclass__"); metaclass = PyDict_GetItemString(gl, "__metaclass__");
if (!metaclass) { if (!metaclass) {
metaclass = classobj_cls; metaclass = classobj_cls;
...@@ -978,7 +979,8 @@ Box* typeRepr(BoxedClass* self) { ...@@ -978,7 +979,8 @@ Box* typeRepr(BoxedClass* self) {
Box* m = self->getattr("__module__"); Box* m = self->getattr("__module__");
if (m && m->cls == str_cls) { if (m && m->cls == str_cls) {
BoxedString* sm = static_cast<BoxedString*>(m); BoxedString* sm = static_cast<BoxedString*>(m);
os << sm->s << '.'; if (sm->s != "__builtin__")
os << sm->s << '.';
} }
os << self->tp_name; os << self->tp_name;
......
# expected: fail
g = {}
exec """from import_target import *""" in g
del g['__builtins__']
print sorted(g.keys())
...@@ -46,6 +46,7 @@ f(-1) ...@@ -46,6 +46,7 @@ f(-1)
for i in xrange(1000): for i in xrange(1000):
g['b'] = 6 g['b'] = 6
l['f'](i) l['f'](i)
print l['f'].__module__
print 'Test global access in comprehensions' print 'Test global access in comprehensions'
...@@ -74,3 +75,46 @@ exec_("""global a ...@@ -74,3 +75,46 @@ exec_("""global a
print a print a
print b""", g, l) print b""", g, l)
exec """print __name__"""
exec """print __name__""" in {}, {}
# Test classdefs in execs:
b = 3
a = 2
s = """class C(object):
print "b =", b
if b:
c = 2
else:
a = -1
print a, b
print C.__module__, C.__name__, repr(C)
"""
exec s in {'a': 1, 'b': 5}, {'b': 2}
exec s
# Test old-style classdefs in execs:
b = 3
a = 2
s = """class C():
print "b =", b
if b:
c = 2
else:
a = -1
print a, b
print C.__module__
"""
exec s in {'a': 1, 'b': 5}, {'b': 2}
exec s
# test eval+exec in exec:
a = 5
exec """print eval('a')""" in {'a': 6}, {}
exec """exec 'print a' """ in {'a': 6}, {}
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