Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cheaper frame introspection #1011

Merged
merged 5 commits into from
Dec 4, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 3 additions & 7 deletions src/analysis/scoping_analysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,6 @@ static InternedString mangleName(InternedString id, llvm::StringRef private_name
return rtn;
}

static bool isCompilerCreatedName(llvm::StringRef name) {
return name[0] == '!' || name[0] == '#';
}

class ModuleScopeInfo : public ScopeInfo {
public:
ScopeInfo* getParent() override { return NULL; }
Expand All @@ -121,7 +117,7 @@ class ModuleScopeInfo : public ScopeInfo {
bool passesThroughClosure() override { return false; }

VarScopeType getScopeTypeOfName(InternedString name) override {
if (isCompilerCreatedName(name))
if (name.isCompilerCreatedName())
return VarScopeType::FAST;
else
return VarScopeType::GLOBAL;
Expand Down Expand Up @@ -185,7 +181,7 @@ class EvalExprScopeInfo : public ScopeInfo {
bool passesThroughClosure() override { return false; }

VarScopeType getScopeTypeOfName(InternedString name) override {
if (isCompilerCreatedName(name))
if (name.isCompilerCreatedName())
return VarScopeType::FAST;
else if (forced_globals.find(name) != forced_globals.end())
return VarScopeType::GLOBAL;
Expand Down Expand Up @@ -341,7 +337,7 @@ class ScopeInfoBase : public ScopeInfo {
bool passesThroughClosure() override { return usage->passthrough_accesses.size() > 0 && !createsClosure(); }

VarScopeType getScopeTypeOfName(InternedString name) override {
if (isCompilerCreatedName(name))
if (name.isCompilerCreatedName())
return VarScopeType::FAST;

if (usage->forced_globals.count(name) > 0)
Expand Down
107 changes: 48 additions & 59 deletions src/codegen/ast_interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ class ASTInterpreter {

Box** vregs;
ExcInfo last_exception;
BoxedClosure* passed_closure, *created_closure;
BoxedClosure* created_closure;
BoxedGenerator* generator;
unsigned edgecount;
FrameInfo frame_info;
Expand Down Expand Up @@ -174,7 +174,7 @@ class ASTInterpreter {

FunctionMetadata* getMD() { return md; }
FrameInfo* getFrameInfo() { return &frame_info; }
BoxedClosure* getPassedClosure() { return passed_closure; }
BoxedClosure* getPassedClosure() { return frame_info.passed_closure; }
Box** getVRegs() { return vregs; }
const ScopeInfo* getScopeInfo() { return scope_info; }

Expand Down Expand Up @@ -203,9 +203,9 @@ void ASTInterpreter::setGenerator(Box* gen) {
}

void ASTInterpreter::setPassedClosure(Box* closure) {
assert(!this->passed_closure); // This should only used for initialization
assert(closure->cls == closure_cls);
this->passed_closure = static_cast<BoxedClosure*>(closure);
assert(!frame_info.passed_closure); // This should only used for initialization
assert(!closure || closure->cls == closure_cls);
frame_info.passed_closure = static_cast<BoxedClosure*>(closure);
}

void ASTInterpreter::setCreatedClosure(Box* closure) {
Expand Down Expand Up @@ -236,7 +236,6 @@ ASTInterpreter::ASTInterpreter(FunctionMetadata* md, Box** vregs)
phis(NULL),
vregs(vregs),
last_exception(NULL, NULL, NULL),
passed_closure(0),
created_closure(0),
generator(0),
edgecount(0),
Expand All @@ -246,17 +245,18 @@ ASTInterpreter::ASTInterpreter(FunctionMetadata* md, Box** vregs)
should_jit(false) {

scope_info = source_info->getScopeInfo();
frame_info.vregs = vregs;

assert(scope_info);
}

void ASTInterpreter::initArguments(BoxedClosure* _closure, BoxedGenerator* _generator, Box* arg1, Box* arg2, Box* arg3,
Box** args) {
passed_closure = _closure;
setPassedClosure(_closure);
generator = _generator;

if (scope_info->createsClosure())
created_closure = createClosure(passed_closure, scope_info->getClosureSize());
created_closure = createClosure(_closure, scope_info->getClosureSize());

const ParamNames& param_names = md->param_names;

Expand Down Expand Up @@ -407,17 +407,6 @@ Box* ASTInterpreter::executeInner(ASTInterpreter& interpreter, CFGBlock* start_b

Box* ASTInterpreter::execute(ASTInterpreter& interpreter, CFGBlock* start_block, AST_stmt* start_at) {
UNAVOIDABLE_STAT_TIMER(t0, "us_timer_in_interpreter");

// Note: due to some (avoidable) restrictions, this check is pretty constrained in where
// it can go, due to the fact that it can throw an exception.
// It can't go in the ASTInterpreter constructor, since that will cause the C++ runtime to
// delete the partially-constructed memory which we don't currently handle. It can't go into
// executeInner since we want the SyntaxErrors to happen *before* the stack frame is entered.
// (For instance, throwing the exception will try to fetch the current statement, but we determine
// that by looking at the cfg.)
if (!interpreter.source_info->cfg)
interpreter.source_info->cfg = computeCFG(interpreter.source_info, interpreter.source_info->body);

return executeInnerAndSetupFrame(interpreter, start_block, start_at);
}

Expand Down Expand Up @@ -724,8 +713,8 @@ Box* ASTInterpreter::doOSR(AST_Jump* node) {
if (generator)
sorted_symbol_table[source_info->getInternedStrings().get(PASSED_GENERATOR_NAME)] = generator;

if (passed_closure)
sorted_symbol_table[source_info->getInternedStrings().get(PASSED_CLOSURE_NAME)] = passed_closure;
if (frame_info.passed_closure)
sorted_symbol_table[source_info->getInternedStrings().get(PASSED_CLOSURE_NAME)] = frame_info.passed_closure;

if (created_closure)
sorted_symbol_table[source_info->getInternedStrings().get(CREATED_CLOSURE_NAME)] = created_closure;
Expand Down Expand Up @@ -1038,9 +1027,9 @@ Value ASTInterpreter::createFunction(AST* node, AST_arguments* args, const std::
closure_var = jit->getInterp()->getAttr(offsetof(ASTInterpreter, created_closure));
} else {
assert(scope_info->passesThroughClosure());
closure = passed_closure;
closure = frame_info.passed_closure;
if (jit)
closure_var = jit->getInterp()->getAttr(offsetof(ASTInterpreter, passed_closure));
closure_var = jit->getInterp()->getAttr(offsetof(ASTInterpreter, frame_info.passed_closure));
}
assert(closure);
}
Expand Down Expand Up @@ -1105,7 +1094,7 @@ Value ASTInterpreter::visit_makeClass(AST_MakeClass* mkclass) {
BoxedClosure* closure = NULL;
if (scope_info->takesClosure()) {
if (this->scope_info->passesThroughClosure())
closure = passed_closure;
closure = getPassedClosure();
else
closure = created_closure;
assert(closure);
Expand Down Expand Up @@ -1633,8 +1622,8 @@ void ASTInterpreterJitInterface::delNameHelper(void* _interpreter, InternedStrin
Box* ASTInterpreterJitInterface::derefHelper(void* _interpreter, InternedString s) {
ASTInterpreter* interpreter = (ASTInterpreter*)_interpreter;
DerefInfo deref_info = interpreter->scope_info->getDerefInfo(s);
assert(interpreter->passed_closure);
BoxedClosure* closure = interpreter->passed_closure;
assert(interpreter->getPassedClosure());
BoxedClosure* closure = interpreter->getPassedClosure();
for (int i = 0; i < deref_info.num_parents_from_passed_closure; i++) {
closure = closure->parent;
}
Expand Down Expand Up @@ -1698,28 +1687,6 @@ extern "C" Box* executeInnerFromASM(ASTInterpreter& interpreter, CFGBlock* start
return ASTInterpreter::executeInner(interpreter, start_block, start_at);
}

static int calculateNumVRegs(FunctionMetadata* md) {
SourceInfo* source_info = md->source.get();

CFG* cfg = source_info->cfg;

// Note: due to some (avoidable) restrictions, this check is pretty constrained in where
// it can go, due to the fact that it can throw an exception.
// It can't go in the ASTInterpreter constructor, since that will cause the C++ runtime to
// delete the partially-constructed memory which we don't currently handle. It can't go into
// executeInner since we want the SyntaxErrors to happen *before* the stack frame is entered.
// (For instance, throwing the exception will try to fetch the current statement, but we determine
// that by looking at the cfg.)
if (!cfg)
cfg = source_info->cfg = computeCFG(source_info, source_info->body);

if (!cfg->hasVregsAssigned()) {
ScopeInfo* scope_info = md->source->getScopeInfo();
cfg->assignVRegs(md->param_names, scope_info);
}
return cfg->sym_vreg_map.size();
}

Box* astInterpretFunction(FunctionMetadata* md, Box* closure, Box* generator, Box* globals, Box* arg1, Box* arg2,
Box* arg3, Box** args) {
UNAVOIDABLE_STAT_TIMER(t0, "us_timer_in_interpreter");
Expand Down Expand Up @@ -1785,8 +1752,18 @@ Box* astInterpretFunction(FunctionMetadata* md, Box* closure, Box* generator, Bo
}
}

// Note: due to some (avoidable) restrictions, this check is pretty constrained in where
// it can go, due to the fact that it can throw an exception.
// It can't go in the ASTInterpreter constructor, since that will cause the C++ runtime to
// delete the partially-constructed memory which we don't currently handle. It can't go into
// executeInner since we want the SyntaxErrors to happen *before* the stack frame is entered.
// (For instance, throwing the exception will try to fetch the current statement, but we determine
// that by looking at the cfg.)
if (!source_info->cfg)
source_info->cfg = computeCFG(source_info, source_info->body);

Box** vregs = NULL;
int num_vregs = calculateNumVRegs(md);
int num_vregs = md->calculateNumVRegs();
if (num_vregs > 0) {
vregs = (Box**)alloca(sizeof(Box*) * num_vregs);
memset(vregs, 0, sizeof(Box*) * num_vregs);
Expand Down Expand Up @@ -1816,8 +1793,19 @@ Box* astInterpretFunction(FunctionMetadata* md, Box* closure, Box* generator, Bo
Box* astInterpretFunctionEval(FunctionMetadata* md, Box* globals, Box* boxedLocals) {
++md->times_interpreted;

// Note: due to some (avoidable) restrictions, this check is pretty constrained in where
// it can go, due to the fact that it can throw an exception.
// It can't go in the ASTInterpreter constructor, since that will cause the C++ runtime to
// delete the partially-constructed memory which we don't currently handle. It can't go into
// executeInner since we want the SyntaxErrors to happen *before* the stack frame is entered.
// (For instance, throwing the exception will try to fetch the current statement, but we determine
// that by looking at the cfg.)
SourceInfo* source_info = md->source.get();
if (!source_info->cfg)
source_info->cfg = computeCFG(source_info, source_info->body);

Box** vregs = NULL;
int num_vregs = calculateNumVRegs(md);
int num_vregs = md->calculateNumVRegs();
if (num_vregs > 0) {
vregs = (Box**)alloca(sizeof(Box*) * num_vregs);
memset(vregs, 0, sizeof(Box*) * num_vregs);
Expand Down Expand Up @@ -1848,7 +1836,7 @@ static Box* astInterpretDeoptInner(FunctionMetadata* md, AST_expr* after_expr, A
SourceInfo* source_info = md->source.get();

Box** vregs = NULL;
int num_vregs = calculateNumVRegs(md);
int num_vregs = md->calculateNumVRegs();
if (num_vregs > 0) {
vregs = (Box**)alloca(sizeof(Box*) * num_vregs);
memset(vregs, 0, sizeof(Box*) * num_vregs);
Expand Down Expand Up @@ -1973,15 +1961,16 @@ FrameInfo* getFrameInfoForInterpretedFrame(void* frame_ptr) {
return interpreter->getFrameInfo();
}

BoxedDict* localsForInterpretedFrame(void* frame_ptr, bool only_user_visible) {
Box** getVRegsForInterpretedFrame(void* frame_ptr) {
ASTInterpreter* interpreter = getInterpreterFromFramePtr(frame_ptr);
assert(interpreter);
BoxedDict* rtn = new BoxedDict();
for (auto& l : interpreter->getSymVRegMap()) {
if (only_user_visible && (l.first.s()[0] == '!' || l.first.s()[0] == '#'))
continue;
return interpreter->getVRegs();
}

Box* val = interpreter->getVRegs()[l.second];
BoxedDict* localsForInterpretedFrame(Box** vregs, CFG* cfg) {
BoxedDict* rtn = new BoxedDict();
for (auto& l : cfg->sym_vreg_map_user_visible) {
Box* val = vregs[l.second];
if (val) {
assert(gc::isValidGCObject(val));
rtn->d[l.first.getBox()] = val;
Expand All @@ -1991,9 +1980,9 @@ BoxedDict* localsForInterpretedFrame(void* frame_ptr, bool only_user_visible) {
return rtn;
}

BoxedClosure* passedClosureForInterpretedFrame(void* frame_ptr) {
BoxedDict* localsForInterpretedFrame(void* frame_ptr) {
ASTInterpreter* interpreter = getInterpreterFromFramePtr(frame_ptr);
assert(interpreter);
return interpreter->getPassedClosure();
return localsForInterpretedFrame(interpreter->getVRegs(), interpreter->getMD()->source->cfg);
}
}
5 changes: 3 additions & 2 deletions src/codegen/ast_interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,10 @@ Box* getGlobalsForInterpretedFrame(void* frame_ptr);
FunctionMetadata* getMDForInterpretedFrame(void* frame_ptr);
struct FrameInfo;
FrameInfo* getFrameInfoForInterpretedFrame(void* frame_ptr);
BoxedClosure* passedClosureForInterpretedFrame(void* frame_ptr);

BoxedDict* localsForInterpretedFrame(void* frame_ptr, bool only_user_visible);
Box** getVRegsForInterpretedFrame(void* frame_ptr);
BoxedDict* localsForInterpretedFrame(Box** vregs, CFG* cfg);
BoxedDict* localsForInterpretedFrame(void* frame_ptr);

// Executes the equivalent of CPython's PRINT_EXPR opcode (call sys.displayhook)
extern "C" void printExprHelper(Box* b);
Expand Down
2 changes: 1 addition & 1 deletion src/codegen/baseline_jit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -857,7 +857,7 @@ void JitFragmentWriter::_emitPPCall(RewriterVar* result, void* func_addr, llvm::

// make space for patchpoint
uint8_t* pp_start = rewrite->getSlotStart() + assembler->bytesWritten();
constexpr int call_size = 16;
constexpr int call_size = 13;
assembler->skipBytes(pp_size + call_size);
uint8_t* pp_end = rewrite->getSlotStart() + assembler->bytesWritten();
assert(assembler->hasFailed() || (pp_start + pp_size + call_size == pp_end));
Expand Down
15 changes: 15 additions & 0 deletions src/codegen/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "codegen/baseline_jit.h"
#include "codegen/compvars.h"
#include "core/ast.h"
#include "core/cfg.h"
#include "core/util.h"
#include "runtime/code.h"
#include "runtime/types.h"
Expand Down Expand Up @@ -72,6 +73,20 @@ BoxedCode* FunctionMetadata::getCode() {
return code_obj;
}

int FunctionMetadata::calculateNumVRegs() {
SourceInfo* source_info = source.get();

CFG* cfg = source_info->cfg;
assert(cfg && "We don't calculate the CFG inside this function because it can raise an exception and its "
"therefore not safe to call at every point");

if (!cfg->hasVregsAssigned()) {
ScopeInfo* scope_info = source->getScopeInfo();
cfg->assignVRegs(param_names, scope_info);
}
return cfg->sym_vreg_map.size();
}

void FunctionMetadata::addVersion(CompiledFunction* compiled) {
assert(compiled);
assert((compiled->spec != NULL) + (compiled->entry_descriptor != NULL) == 1);
Expand Down
1 change: 1 addition & 0 deletions src/codegen/entry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,7 @@ void PystonObjectCache::calculateModuleHash(const llvm::Module* M, EffortLevel e
HashOStream hash_stream;
llvm::WriteBitcodeToFile(M, hash_stream);
hash_stream << (int)effort;
hash_stream << USE_REGALLOC_BASIC;
hash_before_codegen = hash_stream.getHash();
}

Expand Down
2 changes: 2 additions & 0 deletions src/codegen/irgen.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ class IREmitter {
virtual void checkAndPropagateCapiException(const UnwindInfo& unw_info, llvm::Value* returned_val,
llvm::Value* exc_val, bool double_check = false) = 0;

virtual llvm::Value* createDeopt(AST_stmt* current_stmt, AST_expr* node, llvm::Value* node_value) = 0;

virtual Box* getIntConstant(int64_t n) = 0;
virtual Box* getFloatConstant(double d) = 0;
};
Expand Down
Loading