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

basic functionality working

parent 39afd252
......@@ -104,6 +104,7 @@ public:
bool usesNameLookup() override { return false; }
bool areLocalsFromModule() override { return true; }
bool areGlobalsFromModule() override { return true; }
DerefInfo getDerefInfo(InternedString) override { RELEASE_ASSERT(0, "This should never get called"); }
size_t getClosureOffset(InternedString) override { RELEASE_ASSERT(0, "This should never get called"); }
......@@ -142,10 +143,12 @@ private:
}
};
bool globals_from_module;
public:
EvalExprScopeInfo() {}
EvalExprScopeInfo(bool globals_from_module) : globals_from_module(globals_from_module) {}
EvalExprScopeInfo(AST* node) {
EvalExprScopeInfo(AST* node, bool globals_from_module) : globals_from_module(globals_from_module) {
// Find all the global statements in the node's scope (not delving into FuncitonDefs
// or ClassDefs) and put the names in `forced_globals`.
GlobalStmtVisitor visitor(forced_globals);
......@@ -170,6 +173,7 @@ public:
bool usesNameLookup() override { return true; }
bool areLocalsFromModule() override { return false; }
bool areGlobalsFromModule() override { return globals_from_module; }
DerefInfo getDerefInfo(InternedString) override { RELEASE_ASSERT(0, "This should never get called"); }
size_t getClosureOffset(InternedString) override { RELEASE_ASSERT(0, "This should never get called"); }
......@@ -321,6 +325,7 @@ public:
bool usesNameLookup() override { return usesNameLookup_; }
bool areLocalsFromModule() override { return false; }
bool areGlobalsFromModule() override { return true; }
DerefInfo getDerefInfo(InternedString name) override {
assert(getScopeTypeOfName(name) == VarScopeType::DEREF);
......@@ -881,12 +886,12 @@ ScopingAnalysis::ScopingAnalysis(AST_Module* m) : parent_module(m), interned_str
scopes[m] = new ModuleScopeInfo();
}
ScopingAnalysis::ScopingAnalysis(AST_Expression* e) : interned_strings(*e->interned_strings.get()) {
ScopingAnalysis::ScopingAnalysis(AST_Expression* e, bool globals_from_module) : interned_strings(*e->interned_strings.get()) {
// It's an expression, so it can't have a `global` statement
scopes[e] = new EvalExprScopeInfo();
scopes[e] = new EvalExprScopeInfo(globals_from_module);
}
ScopingAnalysis::ScopingAnalysis(AST_Suite* s) : interned_strings(*s->interned_strings.get()) {
scopes[s] = new EvalExprScopeInfo(s);
ScopingAnalysis::ScopingAnalysis(AST_Suite* s, bool globals_from_module) : interned_strings(*s->interned_strings.get()) {
scopes[s] = new EvalExprScopeInfo(s, globals_from_module);
}
}
......@@ -92,6 +92,7 @@ public:
virtual bool usesNameLookup() = 0;
virtual bool areLocalsFromModule() = 0;
virtual bool areGlobalsFromModule() = 0;
// For a variable with DEREF lookup, return the DerefInfo used to lookup
// the variable in a passed closure.
......@@ -169,8 +170,8 @@ public:
void registerScopeReplacement(AST* original_node, AST* new_node);
ScopingAnalysis(AST_Module* m);
ScopingAnalysis(AST_Expression* e);
ScopingAnalysis(AST_Suite* s);
ScopingAnalysis(AST_Expression* e, bool globals_from_module);
ScopingAnalysis(AST_Suite* s, bool globals_from_module);
ScopeInfo* getScopeInfoForNode(AST* node);
InternedStringPool& getInternedStrings();
......
......@@ -141,6 +141,9 @@ private:
unsigned edgecount;
FrameInfo frame_info;
// This is either a module or a dict
Box* globals;
public:
AST_stmt* getCurrentStatement() {
assert(current_inst);
......@@ -159,6 +162,7 @@ public:
void setCreatedClosure(Box* closure);
void setBoxedLocals(Box*);
void setFrameInfo(const FrameInfo* frame_info);
void setGlobals(Box* globals);
void gcVisit(GCVisitor* visitor);
};
......@@ -195,6 +199,13 @@ void ASTInterpreter::setFrameInfo(const FrameInfo* frame_info) {
this->frame_info = *frame_info;
}
void ASTInterpreter::setGlobals(Box* globals) {
this->globals = globals;
if (globals->cls == dict_cls) {
frame_info.globals = static_cast<BoxedDict*>(globals);
}
}
void ASTInterpreter::gcVisit(GCVisitor* visitor) {
visitor->visitRange((void* const*)&sym_table.vector()[0], (void* const*)&sym_table.vector()[sym_table.size()]);
if (passed_closure)
......@@ -205,6 +216,8 @@ void ASTInterpreter::gcVisit(GCVisitor* visitor) {
visitor->visit(generator);
if (frame_info.boxedLocals)
visitor->visit(frame_info.boxedLocals);
if (frame_info.globals)
visitor->visit(frame_info.globals);
}
ASTInterpreter::ASTInterpreter(CompiledFunction* compiled_function)
......@@ -217,6 +230,7 @@ ASTInterpreter::ASTInterpreter(CompiledFunction* compiled_function)
source_info->cfg = computeCFG(f->source, f->source->body);
scope_info = source_info->getScopeInfo();
assert(scope_info);
}
......@@ -345,7 +359,12 @@ Value ASTInterpreter::doBinOp(Box* left, Box* right, int op, BinExpType exp_type
void ASTInterpreter::doStore(InternedString name, Value value) {
ScopeInfo::VarScopeType vst = scope_info->getScopeTypeOfName(name);
if (vst == ScopeInfo::VarScopeType::GLOBAL) {
setattr(source_info->parent_module, name.c_str(), value.o);
if (globals->cls == module_cls) {
setattr(static_cast<BoxedModule*>(globals), name.c_str(), value.o);
} else {
assert(globals->cls == dict_cls);
static_cast<BoxedDict*>(globals)->d[boxString(name.str())] = value.o;
}
} else if (vst == ScopeInfo::VarScopeType::NAME) {
assert(frame_info.boxedLocals != NULL);
// TODO should probably pre-box the names when it's a scope that usesNameLookup
......@@ -819,7 +838,7 @@ Value ASTInterpreter::visit_delete(AST_Delete* node) {
ScopeInfo::VarScopeType vst = scope_info->getScopeTypeOfName(target->id);
if (vst == ScopeInfo::VarScopeType::GLOBAL) {
// Can't use delattr since the errors are different:
delGlobal(source_info->parent_module, &target->id.str());
delGlobal(globals, &target->id.str());
continue;
} else if (vst == ScopeInfo::VarScopeType::NAME) {
assert(frame_info.boxedLocals != NULL);
......@@ -1084,7 +1103,7 @@ Value ASTInterpreter::visit_name(AST_Name* node) {
switch (node->lookup_type) {
case ScopeInfo::VarScopeType::GLOBAL:
return getGlobal(source_info->parent_module, &node->id.str());
return getGlobal(globals, &node->id.str());
case ScopeInfo::VarScopeType::DEREF: {
DerefInfo deref_info = scope_info->getDerefInfo(node->id);
assert(passed_closure);
......@@ -1109,7 +1128,7 @@ Value ASTInterpreter::visit_name(AST_Name* node) {
return Value();
}
case ScopeInfo::VarScopeType::NAME: {
return boxedLocalsGet(frame_info.boxedLocals, node->id.c_str(), source_info->parent_module);
return boxedLocalsGet(frame_info.boxedLocals, node->id.c_str(), globals);
}
default:
abort();
......@@ -1161,22 +1180,39 @@ Box* astInterpretFunction(CompiledFunction* cf, int nargs, Box* closure, Box* ge
++cf->times_called;
ASTInterpreter interpreter(cf);
if (unlikely(cf->clfunc->source->getScopeInfo()->usesNameLookup())) {
ScopeInfo* scope_info = cf->clfunc->source->getScopeInfo();
SourceInfo* source_info = cf->clfunc->source;
if (unlikely(scope_info->usesNameLookup())) {
interpreter.setBoxedLocals(new BoxedDict());
}
assert(scope_info->areGlobalsFromModule());
interpreter.setGlobals(source_info->parent_module);
interpreter.initArguments(nargs, (BoxedClosure*)closure, (BoxedGenerator*)generator, arg1, arg2, arg3, args);
Value v = ASTInterpreter::execute(interpreter);
return v.o ? v.o : None;
}
Box* astInterpretFunctionEval(CompiledFunction* cf, Box* boxedLocals) {
Box* astInterpretFunctionEval(CompiledFunction* cf, BoxedDict* globals, Box* boxedLocals) {
++cf->times_called;
ASTInterpreter interpreter(cf);
interpreter.initArguments(0, NULL, NULL, NULL, NULL, NULL, NULL);
interpreter.setBoxedLocals(boxedLocals);
ScopeInfo* scope_info = cf->clfunc->source->getScopeInfo();
SourceInfo* source_info = cf->clfunc->source;
if (scope_info->areGlobalsFromModule()) {
assert(!globals);
interpreter.setGlobals(source_info->parent_module);
} else {
assert(globals);
interpreter.setGlobals(globals);
}
Value v = ASTInterpreter::execute(interpreter);
return v.o ? v.o : None;
......@@ -1192,6 +1228,15 @@ Box* astInterpretFrom(CompiledFunction* cf, AST_expr* after_expr, AST_stmt* encl
ASTInterpreter interpreter(cf);
ScopeInfo* scope_info = cf->clfunc->source->getScopeInfo();
SourceInfo* source_info = cf->clfunc->source;
if (scope_info->areGlobalsFromModule()) {
interpreter.setGlobals(source_info->parent_module);
} else {
assert(frame_state.frame_info->globals);
interpreter.setGlobals(frame_state.frame_info->globals);
}
for (const auto& p : frame_state.locals->d) {
assert(p.first->cls == str_cls);
std::string name = static_cast<BoxedString*>(p.first)->s;
......
......@@ -35,7 +35,7 @@ extern const void* interpreter_instr_addr;
Box* astInterpretFunction(CompiledFunction* f, int nargs, Box* closure, Box* generator, Box* arg1, Box* arg2, Box* arg3,
Box** args);
Box* astInterpretFunctionEval(CompiledFunction* cf, Box* boxedLocals);
Box* astInterpretFunctionEval(CompiledFunction* cf, BoxedDict* globals, Box* boxedLocals);
Box* astInterpretFrom(CompiledFunction* cf, AST_expr* after_expr, AST_stmt* enclosing_stmt, Box* expr_val,
FrameStackState frame_state);
......
......@@ -327,7 +327,7 @@ void compileAndRunModule(AST_Module* m, BoxedModule* bm) {
}
template <typename AST_Type>
Box* evalOrExec(AST_Type* source, std::vector<AST_stmt*>& body, BoxedModule* bm, Box* boxedLocals) {
Box* evalOrExec(AST_Type* source, std::vector<AST_stmt*>& body, BoxedModule* bm, BoxedDict* globals, Box* boxedLocals) {
CompiledFunction* cf;
{ // scope for limiting the locked region:
......@@ -335,7 +335,7 @@ Box* evalOrExec(AST_Type* source, std::vector<AST_stmt*>& body, BoxedModule* bm,
Timer _t("for evalOrExec()");
ScopingAnalysis* scoping = new ScopingAnalysis(source);
ScopingAnalysis* scoping = new ScopingAnalysis(source, globals == NULL);
SourceInfo* si = new SourceInfo(bm, scoping, source, body);
CLFunction* cl_f = new CLFunction(0, 0, false, false, si);
......@@ -352,7 +352,7 @@ Box* evalOrExec(AST_Type* source, std::vector<AST_stmt*>& body, BoxedModule* bm,
assert(cf->clfunc->versions.size());
}
return astInterpretFunctionEval(cf, boxedLocals);
return astInterpretFunctionEval(cf, globals, boxedLocals);
}
// Main entrypoints for eval and exec.
......@@ -376,7 +376,7 @@ Box* eval(Box* boxedCode) {
stmt->value = parsedExpr->body;
std::vector<AST_stmt*> body = { stmt };
return evalOrExec<AST_Expression>(parsedExpr, body, module, boxedLocals);
return evalOrExec<AST_Expression>(parsedExpr, body, module, NULL, boxedLocals);
}
Box* exec(Box* boxedCode, Box* globals, Box* locals) {
......@@ -392,6 +392,8 @@ Box* exec(Box* boxedCode, Box* globals, Box* locals) {
BoxedModule* module = getCurrentModule();
assert(!globals || globals->cls == dict_cls);
// TODO same issues as in `eval`
RELEASE_ASSERT(boxedCode->cls == str_cls, "");
const char* code = static_cast<BoxedString*>(boxedCode)->s.c_str();
......@@ -399,7 +401,7 @@ Box* exec(Box* boxedCode, Box* globals, Box* locals) {
AST_Suite* parsedSuite = new AST_Suite(std::move(parsedModule->interned_strings));
parsedSuite->body = parsedModule->body;
return evalOrExec<AST_Suite>(parsedSuite, parsedSuite->body, module, locals);
return evalOrExec<AST_Suite>(parsedSuite, parsedSuite->body, module, static_cast<BoxedDict*>(globals), locals);
}
// If a function version keeps failing its speculations, kill it (remove it
......
......@@ -567,8 +567,9 @@ struct FrameInfo {
ExcInfo exc;
Box* boxedLocals;
BoxedDict* globals;
FrameInfo(ExcInfo exc) : exc(exc), boxedLocals(NULL) {}
FrameInfo(ExcInfo exc) : exc(exc), boxedLocals(NULL), globals(NULL) {}
};
struct CallattrFlags {
......
......@@ -4245,14 +4245,24 @@ Box* typeCall(Box* obj, BoxedTuple* vararg, BoxedDict* kwargs) {
return typeCallInternal(NULL, NULL, ArgPassSpec(n + 1, 0, false, true), arg1, arg2, arg3, args, NULL);
}
extern "C" void delGlobal(BoxedModule* m, const std::string* name) {
if (!m->getattr(*name)) {
raiseExcHelper(NameError, "name '%s' is not defined", name->c_str());
extern "C" void delGlobal(Box* globals, const std::string* name) {
if (globals->cls == module_cls) {
BoxedModule* m = static_cast<BoxedModule*>(globals);
if (!m->getattr(*name)) {
raiseExcHelper(NameError, "name '%s' is not defined", name->c_str());
}
m->delattr(*name, NULL);
} else {
assert(globals->cls == dict_cls);
BoxedDict* d = static_cast<BoxedDict*>(globals);
auto it = d->d.find(boxString(*name));
assertNameDefined(it != d->d.end(), name->c_str(), NameError, false /* local_var_msg */);
d->d.erase(it);
}
m->delattr(*name, NULL);
}
extern "C" Box* getGlobal(BoxedModule* m, const std::string* name) {
extern "C" Box* getGlobal(Box* globals, const std::string* name) {
static StatCounter slowpath_getglobal("slowpath_getglobal");
slowpath_getglobal.log();
static StatCounter nopatch_getglobal("nopatch_getglobal");
......@@ -4270,25 +4280,44 @@ extern "C" Box* getGlobal(BoxedModule* m, const std::string* name) {
Rewriter::createRewriter(__builtin_extract_return_addr(__builtin_return_address(0)), 3, "getGlobal"));
Box* r;
if (rewriter.get()) {
// rewriter->trap();
if (globals->cls == module_cls) {
BoxedModule* m = static_cast<BoxedModule*>(globals);
if (rewriter.get()) {
RewriterVar* r_mod = rewriter->getArg(0);
GetattrRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0), rewriter->getReturnDestination());
r = m->getattr(*name, &rewrite_args);
if (!rewrite_args.out_success) {
rewriter.reset(NULL);
}
if (r) {
if (rewriter.get()) {
rewriter->commitReturning(rewrite_args.out_rtn);
// Guard on it being a module rather than a dict
// TODO is this guard necessary? I'm being conservative now, but I think we can just
// insist that the type passed in is fixed for any given instance of a getGlobal call.
r_mod->addAttrGuard(BOX_CLS_OFFSET, (intptr_t)module_cls);
GetattrRewriteArgs rewrite_args(rewriter.get(), r_mod, rewriter->getReturnDestination());
r = m->getattr(*name, &rewrite_args);
if (!rewrite_args.out_success) {
rewriter.reset(NULL);
}
if (r) {
if (rewriter.get()) {
rewriter->commitReturning(rewrite_args.out_rtn);
}
return r;
}
} else {
r = m->getattr(*name, NULL);
nopatch_getglobal.log();
if (r) {
return r;
}
return r;
}
} else {
r = m->getattr(*name, NULL);
nopatch_getglobal.log();
if (r) {
return r;
assert(globals->cls == dict_cls);
BoxedDict* d = static_cast<BoxedDict*>(globals);
rewriter.reset(NULL);
REWRITE_ABORTED("Rewriting not implemented for getGlobals with a dict globals yet");
auto it = d->d.find(boxString(*name));
if (it != d->d.end()) {
return it->second;
}
}
......@@ -4408,8 +4437,7 @@ extern "C" void boxedLocalsSet(Box* boxedLocals, const char* attr, Box* val) {
setitem(boxedLocals, boxString(attr), val);
}
extern "C" Box* boxedLocalsGet(Box* boxedLocals, const char* attr, BoxedModule* parent_module) {
assert(parent_module->cls == module_cls);
extern "C" Box* boxedLocalsGet(Box* boxedLocals, const char* attr, Box* globals) {
assert(boxedLocals != NULL);
if (boxedLocals->cls == dict_cls) {
......@@ -4434,7 +4462,7 @@ extern "C" Box* boxedLocalsGet(Box* boxedLocals, const char* attr, BoxedModule*
// TODO exception name?
std::string attr_string(attr);
return getGlobal(parent_module, &attr_string);
return getGlobal(globals, &attr_string);
}
extern "C" void boxedLocalsDel(Box* boxedLocals, const char* attr) {
......
......@@ -72,8 +72,6 @@ extern "C" BoxedInt* len(Box* obj);
extern "C" i64 unboxedLen(Box* obj);
extern "C" Box* binop(Box* lhs, Box* rhs, int op_type);
extern "C" Box* augbinop(Box* lhs, Box* rhs, int op_type);
extern "C" Box* getGlobal(BoxedModule* m, const std::string* name);
extern "C" void delGlobal(BoxedModule* m, const std::string* name);
extern "C" Box* getitem(Box* value, Box* slice);
extern "C" void setitem(Box* target, Box* slice, Box* value);
extern "C" void delitem(Box* target, Box* slice);
......@@ -168,8 +166,13 @@ inline std::tuple<Box*, Box*, Box*, Box**> getTupleFromArgsArray(Box** args, int
return std::make_tuple(arg1, arg2, arg3, argtuple);
}
// The `globals` argument can be either a BoxedModule or a BoxedDict
extern "C" Box* getGlobal(Box* globals, const std::string* name);
extern "C" void delGlobal(Box* globals, const std::string* name);
extern "C" void boxedLocalsSet(Box* boxedLocals, const char* attr, Box* val);
extern "C" Box* boxedLocalsGet(Box* boxedLocals, const char* attr, BoxedModule* parent_module);
extern "C" Box* boxedLocalsGet(Box* boxedLocals, const char* attr, Box* globals);
extern "C" void boxedLocalsDel(Box* boxedLocals, const char* attr);
}
#endif
print 'Test getting'
g = {'a': 1}
l = {'b': 2}
exec """global a
print a
print b""" in g, l
print 'Test setting'
g = {}
l = {}
exec """global a
a = 1
b = 2""" in g, l
print g
print l
print 'Test deleting'
g = {'a': 1}
l = {'b': 2}
exec """global a
del a
del b""" in g, l
print g
print l
print 'Test global access in a function'
g = {'a': 4, 'b': 5}
exec """
def f():
global a, b, c
print 'a =', a
del b
c = 20
f()
""" 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