Commit d74e336f authored by Kevin Modzelewski's avatar Kevin Modzelewski

Change the way we pass line numbers to the runtime

Before, for compiled functions we used dwarf line number information.

Now it's switched to using the new frame introspection support, and
we pass through the AST_stmt* as one of the arguments.  This gets us
the line number and also the definition of execution point.
parent 048c730d
......@@ -900,7 +900,7 @@ watch_%:
TARGET=$(dir $@)$(patsubst watch_%,%,$(notdir $@)); \
clear; $(MAKE) $$TARGET $(WATCH_ARGS); true; \
while inotifywait -q -e modify -e attrib -e move -e move_self -e create -e delete -e delete_self \
Makefile $$(find .. \( -name '*.cpp' -o -name '*.h' -o -name '*.py' \) ); do clear; $(MAKE) $$TARGET $(WATCH_ARGS); done )
Makefile $$(find . \( -name '*.cpp' -o -name '*.h' -o -name '*.py' \) ); do clear; $(MAKE) $$TARGET $(WATCH_ARGS); done )
# Makefile $$(find \( -name '*.cpp' -o -name '*.h' -o -name '*.py' \) -o -type d ); do clear; $(MAKE) $(patsubst watch_%,%,$@); done )
# -r . ; do clear; $(MAKE) $(patsubst watch_%,%,$@); done
watch: watch_pyston_dbg
......
......@@ -65,7 +65,7 @@ public:
void initArguments(int nargs, BoxedClosure* closure, BoxedGenerator* generator, Box* arg1, Box* arg2, Box* arg3,
Box** args);
static Value execute(ASTInterpreter& interpreter, AST* start_at = NULL);
static Value execute(ASTInterpreter& interpreter, AST_stmt* start_at = NULL);
private:
Box* createFunction(AST* node, AST_arguments* args, const std::vector<AST_stmt*>& body);
......@@ -122,15 +122,19 @@ private:
SymMap sym_table;
CFGBlock* next_block, *current_block;
AST* current_inst;
AST_stmt* current_inst;
Box* last_exception;
BoxedClosure* passed_closure, *created_closure;
BoxedGenerator* generator;
unsigned edgecount;
public:
LineInfo* getCurrentLineInfo();
BoxedModule* getParentModule() { return source_info->parent_module; }
AST_stmt* getCurrentStatement() {
assert(current_inst);
return current_inst;
}
CompiledFunction* getCF() { return compiled_func; }
const SymMap& getSymbolTable() { return sym_table; }
};
......@@ -162,25 +166,26 @@ Box* astInterpretFunction(CompiledFunction* cf, int nargs, Box* closure, Box* ge
return v.o ? v.o : None;
}
const LineInfo* getLineInfoForInterpretedFrame(void* frame_ptr) {
ASTInterpreter* interpreter = s_interpreterMap[frame_ptr];
assert(interpreter);
return interpreter->getCurrentLineInfo();
}
Box* astInterpretFrom(CompiledFunction* cf, AST_stmt* start_at, BoxedDict* locals) {
assert(locals->d.size() == 0);
ASTInterpreter interpreter(cf);
Value v = ASTInterpreter::execute(interpreter, start_at);
LineInfo* ASTInterpreter::getCurrentLineInfo() {
if (!current_inst)
return NULL;
return v.o ? v.o : None;
}
LineInfo* line_info = new LineInfo(current_inst->lineno, current_inst->col_offset, source_info->parent_module->fn,
source_info->getName());
return line_info;
AST_stmt* getCurrentStatementForInterpretedFrame(void* frame_ptr) {
ASTInterpreter* interpreter = s_interpreterMap[frame_ptr];
assert(interpreter);
return interpreter->getCurrentStatement();
}
BoxedModule* getModuleForInterpretedFrame(void* frame_ptr) {
CompiledFunction* getCFForInterpretedFrame(void* frame_ptr) {
ASTInterpreter* interpreter = s_interpreterMap[frame_ptr];
assert(interpreter);
return interpreter->getParentModule();
return interpreter->getCF();
}
BoxedDict* localsForInterpretedFrame(void* frame_ptr, bool only_user_visible) {
......@@ -263,7 +268,7 @@ public:
};
}
Value ASTInterpreter::execute(ASTInterpreter& interpreter, AST* start_at) {
Value ASTInterpreter::execute(ASTInterpreter& interpreter, AST_stmt* start_at) {
assert(start_at == NULL);
void* frame_addr = __builtin_frame_address(0);
......
......@@ -21,10 +21,9 @@ namespace gc {
class GCVisitor;
}
class AST;
class AST_stmt;
class Box;
class BoxedDict;
class BoxedModule;
struct CompiledFunction;
struct LineInfo;
......@@ -32,9 +31,10 @@ 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* astInterpretFrom(CompiledFunction* cf, AST_stmt* start_at, BoxedDict* locals);
const LineInfo* getLineInfoForInterpretedFrame(void* frame_ptr);
BoxedModule* getModuleForInterpretedFrame(void* frame_ptr);
AST_stmt* getCurrentStatementForInterpretedFrame(void* frame_ptr);
CompiledFunction* getCFForInterpretedFrame(void* frame_ptr);
void gatherInterpreterRoots(gc::GCVisitor* visitor);
BoxedDict* localsForInterpretedFrame(void* frame_ptr, bool only_user_visible);
......
......@@ -25,18 +25,23 @@
namespace pyston {
class AST_expr;
class AST_stmt;
class GCBuilder;
class IREmitter;
struct UnwindInfo {
public:
AST_stmt* current_stmt;
llvm::BasicBlock* exc_dest;
bool needsInvoke() { return exc_dest != NULL; }
UnwindInfo(llvm::BasicBlock* exc_dest) : exc_dest(exc_dest) {}
UnwindInfo(AST_stmt* current_stmt, llvm::BasicBlock* exc_dest) : current_stmt(current_stmt), exc_dest(exc_dest) {}
static UnwindInfo none() { return UnwindInfo(NULL); }
// Risky! This means that we can't unwind from this location, and should be used in the
// rare case that there are language-specific reasons that the statement should not unwind
// (ex: loading function arguments into the appropriate scopes).
static UnwindInfo cantUnwind() { return UnwindInfo(NULL, NULL); }
};
// TODO get rid of this
......
......@@ -138,18 +138,6 @@ static void compileIR(CompiledFunction* cf, EffortLevel::EffortLevel effort) {
delete stackmap;
}
static std::unordered_map<std::string, CompiledFunction*> machine_name_to_cf;
CompiledFunction* cfForMachineFunctionName(const std::string& machine_name) {
assert(machine_name.size());
auto r = machine_name_to_cf[machine_name];
return r;
}
void registerMachineName(const std::string& machine_name, CompiledFunction* cf) {
assert(machine_name_to_cf.count(machine_name) == 0);
machine_name_to_cf[machine_name] = cf;
}
// Compiles a new version of the function with the given signature and adds it to the list;
// should only be called after checking to see if the other versions would work.
// The codegen_lock needs to be held in W mode before calling this function:
......@@ -208,7 +196,6 @@ CompiledFunction* compileFunction(CLFunction* f, FunctionSpecialization* spec, E
cf = new CompiledFunction(0, spec, true, NULL, NULL, effort, 0);
} else {
cf = doCompile(source, entry, effort, spec, name);
registerMachineName(cf->func->getName(), cf);
compileIR(cf, effort);
}
......
......@@ -142,7 +142,7 @@ private:
pp_args.insert(pp_args.end(), ic_stackmap_args.begin(), ic_stackmap_args.end());
irgenerator->addFrameStackmapArgs(info, pp_args);
irgenerator->addFrameStackmapArgs(info, unw_info.current_stmt, pp_args);
llvm::Intrinsic::ID intrinsic_id;
if (return_type->isIntegerTy() || return_type->isPointerTy()) {
......@@ -1336,7 +1336,7 @@ private:
CompilerVariable* closure = _getFake(CREATED_CLOSURE_NAME, false);
assert(closure);
closure->setattr(emitter, getEmptyOpInfo(UnwindInfo::none()), &name, val);
closure->setattr(emitter, getEmptyOpInfo(unw_info), &name, val);
}
}
}
......@@ -2055,7 +2055,7 @@ private:
endBlock(DEAD);
}
void doStmt(AST* node, UnwindInfo unw_info) {
void doStmt(AST_stmt* node, UnwindInfo unw_info) {
// printf("%d stmt: %d\n", node->type, node->lineno);
if (node->lineno) {
emitter.getBuilder()->SetCurrentDebugLocation(
......@@ -2113,7 +2113,7 @@ private:
case AST_TYPE::Invoke: {
assert(!unw_info.needsInvoke());
AST_Invoke* invoke = ast_cast<AST_Invoke>(node);
doStmt(invoke->stmt, UnwindInfo(entry_blocks[invoke->exc_dest]));
doStmt(invoke->stmt, UnwindInfo(node, entry_blocks[invoke->exc_dest]));
assert(state == RUNNING || state == DEAD);
if (state == RUNNING) {
......@@ -2234,8 +2234,14 @@ private:
}
public:
void addFrameStackmapArgs(PatchpointInfo* pp, std::vector<llvm::Value*>& stackmap_args) override {
void addFrameStackmapArgs(PatchpointInfo* pp, AST_stmt* current_stmt,
std::vector<llvm::Value*>& stackmap_args) override {
int initial_args = stackmap_args.size();
assert(INT->llvmType() == g.i64);
stackmap_args.push_back(getConstantInt((uint64_t)current_stmt, g.i64));
pp->addFrameVar("!current_stmt", INT);
if (ENABLE_FRAME_INTROSPECTION) {
// TODO: don't need to use a sorted symbol table if we're explicitly recording the names!
// nice for debugging though.
......@@ -2406,16 +2412,16 @@ public:
if (arg_names.args) {
int i = 0;
for (; i < arg_names.args->size(); i++) {
loadArgument((*arg_names.args)[i], arg_types[i], python_parameters[i], UnwindInfo::none());
loadArgument((*arg_names.args)[i], arg_types[i], python_parameters[i], UnwindInfo::cantUnwind());
}
if (arg_names.vararg->size()) {
loadArgument(*arg_names.vararg, arg_types[i], python_parameters[i], UnwindInfo::none());
loadArgument(*arg_names.vararg, arg_types[i], python_parameters[i], UnwindInfo::cantUnwind());
i++;
}
if (arg_names.kwarg->size()) {
loadArgument(*arg_names.kwarg, arg_types[i], python_parameters[i], UnwindInfo::none());
loadArgument(*arg_names.kwarg, arg_types[i], python_parameters[i], UnwindInfo::cantUnwind());
i++;
}
......@@ -2424,12 +2430,11 @@ public:
}
void run(const CFGBlock* block) override {
UnwindInfo unw_info = UnwindInfo::none();
for (int i = 0; i < block->body.size(); i++) {
if (state == DEAD)
break;
assert(state != FINISHED);
doStmt(block->body[i], unw_info);
doStmt(block->body[i], UnwindInfo(block->body[i], NULL));
}
}
......
......@@ -198,7 +198,8 @@ public:
virtual void run(const CFGBlock* block) = 0;
virtual EndingState getEndingSymbolTable() = 0;
virtual void doSafePoint() = 0;
virtual void addFrameStackmapArgs(PatchpointInfo* pp, std::vector<llvm::Value*>& stackmap_args) = 0;
virtual void addFrameStackmapArgs(PatchpointInfo* pp, AST_stmt* current_stmt,
std::vector<llvm::Value*>& stackmap_args) = 0;
};
class IREmitter;
......
......@@ -152,8 +152,10 @@ void processStackmap(CompiledFunction* cf, StackMap* stackmap) {
PatchpointInfo* pp = reinterpret_cast<PatchpointInfo*>(r->id);
assert(pp);
if (VERBOSITY())
printf("Processing pp %ld\n", reinterpret_cast<int64_t>(pp));
if (VERBOSITY()) {
printf("Processing pp %ld; [%d, %d)\n", reinterpret_cast<int64_t>(pp), r->offset,
r->offset + pp->patchpointSize());
}
assert(r->locations.size() == pp->totalStackmapArgs());
......
......@@ -101,8 +101,6 @@ public:
std::unique_ptr<llvm::DIContext> Context(llvm::DIContext::getDWARFContext(*Obj.getObjectFile()));
assert(g.cur_cf);
assert(!g.cur_cf->line_table);
LineTable* line_table = g.cur_cf->line_table = new LineTable();
llvm_error_code ec;
for (llvm::object::symbol_iterator I = Obj.begin_symbols(), E = Obj.end_symbols(); I != E && !ec; ++I) {
......@@ -141,11 +139,6 @@ public:
g.cur_cf->code_start = Addr;
g.cur_cf->code_size = Size;
cf_registry.registerCF(g.cur_cf);
for (const auto& p : lines) {
line_table->entries.push_back(std::make_pair(
p.first, LineInfo(p.second.Line, p.second.Column, p.second.FileName, p.second.FunctionName)));
}
}
}
......@@ -236,8 +229,9 @@ private:
unw_context_t ctx;
unw_cursor_t cursor;
CompiledFunction* cf;
bool cur_is_osr;
PythonFrameIterator() {}
PythonFrameIterator() : cf(NULL), cur_is_osr(false) {}
// not copyable or movable, since 'cursor' holds an internal pointer to 'ctx'
PythonFrameIterator(const PythonFrameIterator&) = delete;
......@@ -251,6 +245,55 @@ public:
return cf;
}
uint64_t readLocation(const StackMap::Record::Location& loc) {
if (loc.type == StackMap::Record::Location::LocationType::Register) {
// TODO: need to make sure we deal with patchpoints appropriately
return getReg(loc.regnum);
} else if (loc.type == StackMap::Record::Location::LocationType::Indirect) {
uint64_t reg_val = getReg(loc.regnum);
uint64_t addr = reg_val + loc.offset;
return *reinterpret_cast<uint64_t*>(addr);
} else if (loc.type == StackMap::Record::Location::LocationType::Constant) {
return loc.offset;
} else if (loc.type == StackMap::Record::Location::LocationType::ConstIndex) {
int const_idx = loc.offset;
assert(const_idx >= 0);
assert(const_idx < cf->location_map->constants.size());
return getCF()->location_map->constants[const_idx];
} else {
printf("%d %d %d %d\n", loc.type, loc.flags, loc.regnum, loc.offset);
abort();
}
}
AST_stmt* getCurrentStatement() {
if (id.type == PythonFrameId::COMPILED) {
CompiledFunction* cf = getCF();
uint64_t ip = getId().ip;
assert(ip > cf->code_start);
unsigned offset = ip - cf->code_start;
assert(cf->location_map);
const LocationMap::LocationTable& table = cf->location_map->names["!current_stmt"];
assert(table.locations.size());
// printf("Looking for something at offset %d (total ip: %lx)\n", offset, ip);
for (const LocationMap::LocationTable::LocationEntry& e : table.locations) {
// printf("(%d, %d]\n", e.offset, e.offset + e.length);
if (e.offset < offset && offset <= e.offset + e.length) {
// printf("Found it\n");
assert(e.locations.size() == 1);
return reinterpret_cast<AST_stmt*>(readLocation(e.locations[0]));
}
}
abort();
} else if (id.type == PythonFrameId::INTERPRETED) {
return getCurrentStatementForInterpretedFrame((void*)id.bp);
}
abort();
}
const PythonFrameId& getId() const { return id; }
static std::unique_ptr<PythonFrameIterator> end() { return std::unique_ptr<PythonFrameIterator>(nullptr); }
......@@ -279,6 +322,8 @@ public:
}
bool incr() {
bool was_osr = cur_is_osr;
while (true) {
int r = unw_step(&this->cursor);
......@@ -289,8 +334,7 @@ public:
unw_word_t ip;
unw_get_reg(&this->cursor, UNW_REG_IP, &ip);
CompiledFunction* cf = getCFForAddress(ip);
this->cf = cf;
cf = getCFForAddress(ip);
if (cf) {
this->id.type = PythonFrameId::COMPILED;
this->id.ip = ip;
......@@ -298,6 +342,13 @@ public:
unw_word_t bp;
unw_get_reg(&this->cursor, UNW_TDEP_BP, &bp);
cur_is_osr = (bool)cf->entry_descriptor;
if (was_osr) {
// Skip the frame we just found if the previous one was its OSR
// TODO this will break if we start collapsing the OSR frames
return incr();
}
return true;
}
......@@ -313,6 +364,15 @@ public:
this->id.type = PythonFrameId::INTERPRETED;
this->id.bp = bp;
cf = getCFForInterpretedFrame((void*)bp);
cur_is_osr = (bool)cf->entry_descriptor;
if (was_osr) {
// Skip the frame we just found if the previous one was its OSR
// TODO this will break if we start collapsing the OSR frames
return incr();
}
return true;
}
......@@ -368,15 +428,12 @@ static std::unique_ptr<PythonFrameIterator> getTopPythonFrame() {
return fr;
}
static const LineInfo* lineInfoForFrame(const PythonFrameIterator& frame_it) {
auto& id = frame_it.getId();
switch (id.type) {
case PythonFrameId::COMPILED:
return frame_it.getCF()->line_table->getLineInfoFor(id.ip);
case PythonFrameId::INTERPRETED:
return getLineInfoForInterpretedFrame((void*)id.bp);
}
abort();
static const LineInfo* lineInfoForFrame(PythonFrameIterator& frame_it) {
AST_stmt* current_stmt = frame_it.getCurrentStatement();
auto* cf = frame_it.getCF();
assert(cf);
return new LineInfo(current_stmt->lineno, current_stmt->col_offset, cf->clfunc->source->parent_module->fn,
cf->clfunc->source->getName());
}
std::vector<const LineInfo*> getTracebackEntries() {
......@@ -398,24 +455,20 @@ const LineInfo* getMostRecentLineInfo() {
}
CompiledFunction* getTopCompiledFunction() {
// TODO This is a bad way to do this...
const LineInfo* last_entry = getMostRecentLineInfo();
assert(last_entry->func.size());
CompiledFunction* cf = cfForMachineFunctionName(last_entry->func);
return cf;
return getTopPythonFrame()->getCF();
}
BoxedModule* getCurrentModule() {
CompiledFunction* compiledFunction = getTopCompiledFunction();
if (compiledFunction)
return compiledFunction->clfunc->source->parent_module;
else {
std::unique_ptr<PythonFrameIterator> frame = getTopPythonFrame();
auto& id = frame->getId();
assert(id.type == PythonFrameId::INTERPRETED);
return getModuleForInterpretedFrame((void*)id.bp);
}
assert(compiledFunction);
return compiledFunction->clfunc->source->parent_module;
}
ExecutionPoint getExecutionPoint() {
auto frame = getTopPythonFrame();
auto cf = frame->getCF();
auto current_stmt = frame->getCurrentStatement();
return ExecutionPoint({.cf = cf, .current_stmt = current_stmt });
}
BoxedDict* getLocals(bool only_user_visible) {
......@@ -442,28 +495,7 @@ BoxedDict* getLocals(bool only_user_visible) {
// printf("%s: %s\n", p.first.c_str(), e.type->debugName().c_str());
for (auto& loc : locs) {
uint64_t n;
// printf("%d %d %d %d\n", loc.type, loc.flags, loc.regnum, loc.offset);
if (loc.type == StackMap::Record::Location::LocationType::Register) {
// TODO: need to make sure we deal with patchpoints appropriately
n = frame_info.getReg(loc.regnum);
} else if (loc.type == StackMap::Record::Location::LocationType::Indirect) {
uint64_t reg_val = frame_info.getReg(loc.regnum);
uint64_t addr = reg_val + loc.offset;
n = *reinterpret_cast<uint64_t*>(addr);
} else if (loc.type == StackMap::Record::Location::LocationType::Constant) {
n = loc.offset;
} else if (loc.type == StackMap::Record::Location::LocationType::ConstIndex) {
int const_idx = loc.offset;
assert(const_idx >= 0);
assert(const_idx < cf->location_map->constants.size());
n = cf->location_map->constants[const_idx];
} else {
printf("%d %d %d %d\n", loc.type, loc.flags, loc.regnum, loc.offset);
abort();
}
vals.push_back(n);
vals.push_back(frame_info.readLocation(loc));
}
Box* v = e.type->deserializeFromFrame(vals);
......
......@@ -21,19 +21,6 @@
namespace pyston {
class LineTable {
public:
std::vector<std::pair<uint64_t, LineInfo> > entries;
const LineInfo* getLineInfoFor(uint64_t addr) {
for (int i = entries.size() - 1; i >= 0; i--) {
if (entries[i].first < addr)
return &entries[i].second;
}
abort();
}
};
std::vector<const LineInfo*> getTracebackEntries();
const LineInfo* getMostRecentLineInfo();
class BoxedModule;
......@@ -42,6 +29,12 @@ BoxedModule* getCurrentModule();
CompiledFunction* getCFForAddress(uint64_t addr);
class BoxedDict;
BoxedDict* getLocals(bool only_user_visible);
struct ExecutionPoint {
CompiledFunction* cf;
AST_stmt* current_stmt;
};
ExecutionPoint getExecutionPoint();
}
#endif
......@@ -167,7 +167,6 @@ struct FunctionSpecialization {
class BoxedClosure;
class BoxedGenerator;
class LineTable;
class ICInfo;
class LocationMap;
......@@ -196,9 +195,6 @@ public:
int64_t times_called;
ICInvalidator dependent_callsites;
// Unfortunately, can't make this a std::unique_ptr if we want to forward-declare LineTable:
LineTable* line_table;
LocationMap* location_map; // only meaningful if this is a compiled frame
std::vector<ICInfo*> ics;
......@@ -207,8 +203,7 @@ public:
llvm::Value* llvm_code, EffortLevel::EffortLevel effort,
const OSREntryDescriptor* entry_descriptor)
: clfunc(NULL), func(func), spec(spec), entry_descriptor(entry_descriptor), is_interpreted(is_interpreted),
code(code), llvm_code(llvm_code), effort(effort), times_called(0), line_table(nullptr),
location_map(nullptr) {}
code(code), llvm_code(llvm_code), effort(effort), times_called(0), location_map(nullptr) {}
// TODO this will need to be implemented eventually; things to delete:
// - line_table if it exists
......
......@@ -18,6 +18,7 @@
#include "llvm/Support/FileSystem.h"
#include "codegen/ast_interpreter.h"
#include "codegen/irgen/hooks.h"
#include "codegen/parser.h"
#include "codegen/unwinding.h"
......@@ -583,6 +584,13 @@ Box* locals() {
return getLocals(true /* filter */);
}
Box* deopt() {
auto locals = getLocals(false /* filter */);
auto execution_point = getExecutionPoint();
return astInterpretFrom(execution_point.cf, execution_point.current_stmt, locals);
}
Box* divmod(Box* lhs, Box* rhs) {
return binopInternal(lhs, rhs, AST_TYPE::DivMod, false, NULL);
}
......@@ -808,6 +816,7 @@ void setupBuiltins() {
builtins_module->giveAttr("globals", new BoxedFunction(boxRTFunction((void*)globals, UNKNOWN, 0, 0, false, false)));
builtins_module->giveAttr("locals", new BoxedFunction(boxRTFunction((void*)locals, UNKNOWN, 0, 0, false, false)));
builtins_module->giveAttr("deopt", new BoxedFunction(boxRTFunction((void*)deopt, UNKNOWN, 0, 0, false, false)));
builtins_module->giveAttr("iter", new BoxedFunction(boxRTFunction((void*)getiter, UNKNOWN, 1, 0, false, false)));
......
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