Commit e2975b8e authored by Marius Wachtler's avatar Marius Wachtler

interpreter: Don't GC allocate ASTInterpreter instances.

GC allocating the huge number of large ASTInterpreter instances is slow,
instead add a small wrapper object which gets GC allocated and notifies the ASTInterpreter.
parent caa84b81
...@@ -56,6 +56,7 @@ namespace { ...@@ -56,6 +56,7 @@ namespace {
static BoxedClass* astinterpreter_cls; static BoxedClass* astinterpreter_cls;
class ASTInterpreter; class ASTInterpreter;
class ASTInterpreterGCWrapper;
// Map from stack frame pointers for frames corresponding to ASTInterpreter::execute() to the ASTInterpreter handling // Map from stack frame pointers for frames corresponding to ASTInterpreter::execute() to the ASTInterpreter handling
// them. Used to look up information about that frame. This is used for getting tracebacks, for CPython introspection // them. Used to look up information about that frame. This is used for getting tracebacks, for CPython introspection
...@@ -75,11 +76,12 @@ public: ...@@ -75,11 +76,12 @@ public:
static void deregister(void* frame_addr); static void deregister(void* frame_addr);
}; };
class ASTInterpreter : public Box { class ASTInterpreter {
public: public:
typedef ContiguousMap<InternedString, Box*> SymMap; typedef ContiguousMap<InternedString, Box*> SymMap;
ASTInterpreter(CLFunction* clfunc); ASTInterpreter(CLFunction* clfunc);
~ASTInterpreter();
void initArguments(int nargs, BoxedClosure* closure, BoxedGenerator* generator, Box* arg1, Box* arg2, Box* arg3, void initArguments(int nargs, BoxedClosure* closure, BoxedGenerator* generator, Box* arg1, Box* arg2, Box* arg3,
Box** args); Box** args);
...@@ -171,10 +173,9 @@ private: ...@@ -171,10 +173,9 @@ private:
Box* globals; Box* globals;
void* frame_addr; // used to clear entry inside the s_interpreterMap on destruction void* frame_addr; // used to clear entry inside the s_interpreterMap on destruction
std::unique_ptr<JitFragmentWriter> jit; std::unique_ptr<JitFragmentWriter> jit;
ASTInterpreterGCWrapper* wrapper;
public: public:
DEFAULT_CLASS_SIMPLE(astinterpreter_cls);
AST_stmt* getCurrentStatement() { AST_stmt* getCurrentStatement() {
assert(current_inst); assert(current_inst);
return current_inst; return current_inst;
...@@ -199,19 +200,44 @@ public: ...@@ -199,19 +200,44 @@ public:
void setFrameInfo(const FrameInfo* frame_info); void setFrameInfo(const FrameInfo* frame_info);
void setGlobals(Box* globals); void setGlobals(Box* globals);
static void gcHandler(GCVisitor* visitor, Box* box); void gcVisit(GCVisitor* visitor);
static void simpleDestructor(Box* box) {
ASTInterpreter* inter = (ASTInterpreter*)box;
assert(inter->cls == astinterpreter_cls);
if (inter->frame_addr)
RegisterHelper::deregister(inter->frame_addr);
inter->~ASTInterpreter();
}
friend class ASTInterpreterGCWrapper;
friend class RegisterHelper; friend class RegisterHelper;
friend struct pyston::ASTInterpreterJitInterface; friend struct pyston::ASTInterpreterJitInterface;
}; };
// This class makes sure that the fields inside ASTInterpreter instances are visited by the collector and that the
// ASTInterpreter is deregistered from the s_interpreterMap if its unreachable but did not exit. This can happen with
// an ASTInterpreter instance inside a generator which calls yield. If all references to the generator get lost the
// memory get freed but the ASTInterpreter will never exit and therefore not call deregister.
// We could directly GC allocate the ASTInterpreter but this causes a slow down because of the large size and huge
// number of ASTInterpreter instances.
class ASTInterpreterGCWrapper : public Box {
public:
ASTInterpreter* interpreter;
DEFAULT_CLASS_SIMPLE(astinterpreter_cls);
ASTInterpreterGCWrapper(ASTInterpreter* inter) : interpreter(inter) {}
static void gcHandler(GCVisitor* visitor, Box* box) {
ASTInterpreterGCWrapper* wrapper = (ASTInterpreterGCWrapper*)box;
boxGCHandler(visitor, box);
if (wrapper->interpreter)
wrapper->interpreter->gcVisit(visitor);
}
static void simpleDestructor(Box* box) {
ASTInterpreterGCWrapper* wrapper = (ASTInterpreterGCWrapper*)box;
ASTInterpreter* interpreter = wrapper->interpreter;
if (interpreter && interpreter->frame_addr) {
RegisterHelper::deregister(interpreter->frame_addr);
interpreter->~ASTInterpreter();
}
}
};
void ASTInterpreter::addSymbol(InternedString name, Box* value, bool allow_duplicates) { void ASTInterpreter::addSymbol(InternedString name, Box* value, bool allow_duplicates) {
if (!allow_duplicates) if (!allow_duplicates)
assert(sym_table.count(name) == 0); assert(sym_table.count(name) == 0);
...@@ -249,18 +275,15 @@ void ASTInterpreter::setGlobals(Box* globals) { ...@@ -249,18 +275,15 @@ void ASTInterpreter::setGlobals(Box* globals) {
this->globals = globals; this->globals = globals;
} }
void ASTInterpreter::gcHandler(GCVisitor* visitor, Box* box) { void ASTInterpreter::gcVisit(GCVisitor* visitor) {
boxGCHandler(visitor, box); auto&& vec = sym_table.vector();
visitor->visitRange((void* const*)&vec[0], (void* const*)&vec[sym_table.size()]);
ASTInterpreter* interp = (ASTInterpreter*)box; visitor->visit(passed_closure);
auto&& vec = interp->sym_table.vector(); visitor->visit(created_closure);
visitor->visitRange((void* const*)&vec[0], (void* const*)&vec[interp->sym_table.size()]); visitor->visit(generator);
visitor->visit(interp->passed_closure); visitor->visit(globals);
visitor->visit(interp->created_closure); visitor->visit(source_info->parent_module);
visitor->visit(interp->generator); frame_info.gcVisit(visitor);
visitor->visit(interp->globals);
visitor->visit(interp->source_info->parent_module);
interp->frame_info.gcVisit(visitor);
} }
ASTInterpreter::ASTInterpreter(CLFunction* clfunc) ASTInterpreter::ASTInterpreter(CLFunction* clfunc)
...@@ -278,12 +301,17 @@ ASTInterpreter::ASTInterpreter(CLFunction* clfunc) ...@@ -278,12 +301,17 @@ ASTInterpreter::ASTInterpreter(CLFunction* clfunc)
frame_info(ExcInfo(NULL, NULL, NULL)), frame_info(ExcInfo(NULL, NULL, NULL)),
globals(0), globals(0),
frame_addr(0) { frame_addr(0) {
wrapper = new ASTInterpreterGCWrapper(this);
scope_info = source_info->getScopeInfo(); scope_info = source_info->getScopeInfo();
assert(scope_info); assert(scope_info);
} }
ASTInterpreter::~ASTInterpreter() {
wrapper->interpreter = NULL;
}
void ASTInterpreter::initArguments(int nargs, BoxedClosure* _closure, BoxedGenerator* _generator, Box* arg1, Box* arg2, void ASTInterpreter::initArguments(int nargs, BoxedClosure* _closure, BoxedGenerator* _generator, Box* arg1, Box* arg2,
Box* arg3, Box** args) { Box* arg3, Box** args) {
passed_closure = _closure; passed_closure = _closure;
...@@ -1710,22 +1738,22 @@ Box* astInterpretFunction(CLFunction* clfunc, int nargs, Box* closure, Box* gene ...@@ -1710,22 +1738,22 @@ Box* astInterpretFunction(CLFunction* clfunc, int nargs, Box* closure, Box* gene
} }
++clfunc->times_interpreted; ++clfunc->times_interpreted;
ASTInterpreter* interpreter = new ASTInterpreter(clfunc); ASTInterpreter interpreter(clfunc);
ScopeInfo* scope_info = clfunc->source->getScopeInfo(); ScopeInfo* scope_info = clfunc->source->getScopeInfo();
if (unlikely(scope_info->usesNameLookup())) { if (unlikely(scope_info->usesNameLookup())) {
interpreter->setBoxedLocals(new BoxedDict()); interpreter.setBoxedLocals(new BoxedDict());
} }
assert((!globals) == clfunc->source->scoping->areGlobalsFromModule()); assert((!globals) == clfunc->source->scoping->areGlobalsFromModule());
if (globals) { if (globals) {
interpreter->setGlobals(globals); interpreter.setGlobals(globals);
} else { } else {
interpreter->setGlobals(source_info->parent_module); interpreter.setGlobals(source_info->parent_module);
} }
interpreter->initArguments(nargs, (BoxedClosure*)closure, (BoxedGenerator*)generator, arg1, arg2, arg3, args); interpreter.initArguments(nargs, (BoxedClosure*)closure, (BoxedGenerator*)generator, arg1, arg2, arg3, args);
Value v = ASTInterpreter::execute(*interpreter); Value v = ASTInterpreter::execute(interpreter);
return v.o ? v.o : None; return v.o ? v.o : None;
} }
...@@ -1733,18 +1761,18 @@ Box* astInterpretFunction(CLFunction* clfunc, int nargs, Box* closure, Box* gene ...@@ -1733,18 +1761,18 @@ Box* astInterpretFunction(CLFunction* clfunc, int nargs, Box* closure, Box* gene
Box* astInterpretFunctionEval(CLFunction* clfunc, Box* globals, Box* boxedLocals) { Box* astInterpretFunctionEval(CLFunction* clfunc, Box* globals, Box* boxedLocals) {
++clfunc->times_interpreted; ++clfunc->times_interpreted;
ASTInterpreter* interpreter = new ASTInterpreter(clfunc); ASTInterpreter interpreter(clfunc);
interpreter->initArguments(0, NULL, NULL, NULL, NULL, NULL, NULL); interpreter.initArguments(0, NULL, NULL, NULL, NULL, NULL, NULL);
interpreter->setBoxedLocals(boxedLocals); interpreter.setBoxedLocals(boxedLocals);
ScopeInfo* scope_info = clfunc->source->getScopeInfo(); ScopeInfo* scope_info = clfunc->source->getScopeInfo();
SourceInfo* source_info = clfunc->source.get(); SourceInfo* source_info = clfunc->source.get();
assert(!clfunc->source->scoping->areGlobalsFromModule()); assert(!clfunc->source->scoping->areGlobalsFromModule());
assert(globals); assert(globals);
interpreter->setGlobals(globals); interpreter.setGlobals(globals);
Value v = ASTInterpreter::execute(*interpreter); Value v = ASTInterpreter::execute(interpreter);
return v.o ? v.o : None; return v.o ? v.o : None;
} }
...@@ -1757,29 +1785,29 @@ Box* astInterpretFrom(CLFunction* clfunc, AST_expr* after_expr, AST_stmt* enclos ...@@ -1757,29 +1785,29 @@ Box* astInterpretFrom(CLFunction* clfunc, AST_expr* after_expr, AST_stmt* enclos
assert(after_expr); assert(after_expr);
assert(expr_val); assert(expr_val);
ASTInterpreter* interpreter = new ASTInterpreter(clfunc); ASTInterpreter interpreter(clfunc);
ScopeInfo* scope_info = clfunc->source->getScopeInfo(); ScopeInfo* scope_info = clfunc->source->getScopeInfo();
SourceInfo* source_info = clfunc->source.get(); SourceInfo* source_info = clfunc->source.get();
assert(clfunc->source->scoping->areGlobalsFromModule()); assert(clfunc->source->scoping->areGlobalsFromModule());
interpreter->setGlobals(source_info->parent_module); interpreter.setGlobals(source_info->parent_module);
for (const auto& p : frame_state.locals->d) { for (const auto& p : frame_state.locals->d) {
assert(p.first->cls == str_cls); assert(p.first->cls == str_cls);
auto name = static_cast<BoxedString*>(p.first)->s(); auto name = static_cast<BoxedString*>(p.first)->s();
if (name == PASSED_GENERATOR_NAME) { if (name == PASSED_GENERATOR_NAME) {
interpreter->setGenerator(p.second); interpreter.setGenerator(p.second);
} else if (name == PASSED_CLOSURE_NAME) { } else if (name == PASSED_CLOSURE_NAME) {
interpreter->setPassedClosure(p.second); interpreter.setPassedClosure(p.second);
} else if (name == CREATED_CLOSURE_NAME) { } else if (name == CREATED_CLOSURE_NAME) {
interpreter->setCreatedClosure(p.second); interpreter.setCreatedClosure(p.second);
} else { } else {
InternedString interned = clfunc->source->getInternedStrings().get(name); InternedString interned = clfunc->source->getInternedStrings().get(name);
interpreter->addSymbol(interned, p.second, false); interpreter.addSymbol(interned, p.second, false);
} }
} }
interpreter->setFrameInfo(frame_state.frame_info); interpreter.setFrameInfo(frame_state.frame_info);
CFGBlock* start_block = NULL; CFGBlock* start_block = NULL;
AST_stmt* starting_statement = NULL; AST_stmt* starting_statement = NULL;
...@@ -1791,7 +1819,7 @@ Box* astInterpretFrom(CLFunction* clfunc, AST_expr* after_expr, AST_stmt* enclos ...@@ -1791,7 +1819,7 @@ Box* astInterpretFrom(CLFunction* clfunc, AST_expr* after_expr, AST_stmt* enclos
assert(asgn->targets[0]->type == AST_TYPE::Name); assert(asgn->targets[0]->type == AST_TYPE::Name);
auto name = ast_cast<AST_Name>(asgn->targets[0]); auto name = ast_cast<AST_Name>(asgn->targets[0]);
assert(name->id.s()[0] == '#'); assert(name->id.s()[0] == '#');
interpreter->addSymbol(name->id, expr_val, true); interpreter.addSymbol(name->id, expr_val, true);
break; break;
} else if (enclosing_stmt->type == AST_TYPE::Expr) { } else if (enclosing_stmt->type == AST_TYPE::Expr) {
auto expr = ast_cast<AST_Expr>(enclosing_stmt); auto expr = ast_cast<AST_Expr>(enclosing_stmt);
...@@ -1829,7 +1857,7 @@ Box* astInterpretFrom(CLFunction* clfunc, AST_expr* after_expr, AST_stmt* enclos ...@@ -1829,7 +1857,7 @@ Box* astInterpretFrom(CLFunction* clfunc, AST_expr* after_expr, AST_stmt* enclos
assert(starting_statement); assert(starting_statement);
} }
Value v = ASTInterpreter::execute(*interpreter, start_block, starting_statement); Value v = ASTInterpreter::execute(interpreter, start_block, starting_statement);
return v.o ? v.o : None; return v.o ? v.o : None;
} }
...@@ -1879,9 +1907,9 @@ BoxedClosure* passedClosureForInterpretedFrame(void* frame_ptr) { ...@@ -1879,9 +1907,9 @@ BoxedClosure* passedClosureForInterpretedFrame(void* frame_ptr) {
} }
void setupInterpreter() { void setupInterpreter() {
astinterpreter_cls = BoxedHeapClass::create(type_cls, object_cls, ASTInterpreter::gcHandler, 0, 0, astinterpreter_cls = BoxedHeapClass::create(type_cls, object_cls, ASTInterpreterGCWrapper::gcHandler, 0, 0,
sizeof(ASTInterpreter), false, "astinterpreter"); sizeof(ASTInterpreterGCWrapper), false, "astinterpreter");
astinterpreter_cls->simple_destructor = ASTInterpreter::simpleDestructor; astinterpreter_cls->simple_destructor = ASTInterpreterGCWrapper::simpleDestructor;
astinterpreter_cls->freeze(); astinterpreter_cls->freeze();
} }
} }
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