Commit 67c85513 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge branch 'exc_info'

parents c75e90df ee9a3a41
......@@ -969,6 +969,10 @@ test_cpp_ll:
$(CLANGPP_EXE) $(TEST_DIR)/test.cpp -o test.ll -c -O3 -emit-llvm -S -std=c++11 -g
less test.ll
rm test.ll
bench_exceptions:
$(CLANGPP_EXE) $(TEST_DIR)/bench_exceptions.cpp -o bench_exceptions -O3 -std=c++11
zsh -c 'ulimit -v $(MAX_MEM_KB); ulimit -d $(MAX_MEM_KB); time ./bench_exceptions'
rm bench_exceptions
TEST_EXT_MODULE_NAMES := basic_test descr_test slots_test
......
......@@ -371,6 +371,7 @@ private:
case AST_LangPrimitive::IMPORT_NAME:
return UNKNOWN;
case AST_LangPrimitive::NONE:
case AST_LangPrimitive::SET_EXC_INFO:
return NONE;
case AST_LangPrimitive::NONZERO:
return BOOL;
......
......@@ -127,6 +127,7 @@ private:
BoxedClosure* passed_closure, *created_closure;
BoxedGenerator* generator;
unsigned edgecount;
FrameInfo frame_info;
public:
AST_stmt* getCurrentStatement() {
......@@ -135,6 +136,7 @@ public:
}
CompiledFunction* getCF() { return compiled_func; }
FrameInfo* getFrameInfo() { return &frame_info; }
const SymMap& getSymbolTable() { return sym_table; }
void gcVisit(GCVisitor* visitor);
};
......@@ -189,6 +191,12 @@ CompiledFunction* getCFForInterpretedFrame(void* frame_ptr) {
return interpreter->getCF();
}
FrameInfo* getFrameInfoForInterpretedFrame(void* frame_ptr) {
ASTInterpreter* interpreter = s_interpreterMap[frame_ptr];
assert(interpreter);
return interpreter->getFrameInfo();
}
BoxedDict* localsForInterpretedFrame(void* frame_ptr, bool only_user_visible) {
ASTInterpreter* interpreter = s_interpreterMap[frame_ptr];
assert(interpreter);
......@@ -225,7 +233,7 @@ void gatherInterpreterRoots(GCVisitor* visitor) {
ASTInterpreter::ASTInterpreter(CompiledFunction* compiled_function)
: compiled_func(compiled_function), source_info(compiled_function->clfunc->source), scope_info(0), next_block(0),
current_block(0), current_inst(0), last_exception(NULL, NULL, NULL), passed_closure(0), created_closure(0),
generator(0), edgecount(0) {
generator(0), edgecount(0), frame_info(ExcInfo(NULL, NULL, NULL)) {
CLFunction* f = compiled_function->clfunc;
if (!source_info->cfg)
......@@ -590,6 +598,18 @@ Value ASTInterpreter::visit_langPrimitive(AST_LangPrimitive* node) {
assert(node->args.size() == 1);
Value obj = visit_expr(node->args[0]);
v = boxBool(nonzero(obj.o));
} else if (node->opcode == AST_LangPrimitive::SET_EXC_INFO) {
assert(node->args.size() == 3);
Value type = visit_expr(node->args[0]);
assert(type.o);
Value value = visit_expr(node->args[1]);
assert(value.o);
Value traceback = visit_expr(node->args[2]);
assert(traceback.o);
getFrameInfo()->exc = ExcInfo(type.o, value.o, traceback.o);
v = None;
} else
RELEASE_ASSERT(0, "not implemented");
return v;
......
......@@ -35,6 +35,8 @@ Box* astInterpretFrom(CompiledFunction* cf, AST_stmt* start_at, BoxedDict* local
AST_stmt* getCurrentStatementForInterpretedFrame(void* frame_ptr);
CompiledFunction* getCFForInterpretedFrame(void* frame_ptr);
struct FrameInfo;
FrameInfo* getFrameInfoForInterpretedFrame(void* frame_ptr);
void gatherInterpreterRoots(gc::GCVisitor* visitor);
BoxedDict* localsForInterpretedFrame(void* frame_ptr, bool only_user_visible);
......
......@@ -70,6 +70,7 @@ struct GlobalState {
llvm::Type* llvm_class_type, *llvm_class_type_ptr;
llvm::Type* llvm_opaque_type;
llvm::Type* llvm_str_type_ptr;
llvm::Type* frame_info_type;
llvm::Type* llvm_clfunction_type_ptr, *llvm_closure_type_ptr, *llvm_generator_type_ptr;
llvm::Type* llvm_module_type_ptr, *llvm_bool_type_ptr;
llvm::Type* llvm_excinfo_type;
......
......@@ -38,6 +38,7 @@
namespace pyston {
extern "C" void dumpLLVM(llvm::Value* v) {
v->getType()->dump();
v->dump();
}
......@@ -71,6 +72,30 @@ llvm::Value* IRGenState::getScratchSpace(int min_bytes) {
return scratch_space;
}
llvm::Value* IRGenState::getFrameInfoVar() {
if (!frame_info) {
llvm::BasicBlock& entry_block = getLLVMFunction()->getEntryBlock();
llvm::IRBuilder<true> builder(&entry_block);
if (entry_block.begin() != entry_block.end())
builder.SetInsertPoint(&entry_block, entry_block.getFirstInsertionPt());
llvm::AllocaInst* al = builder.CreateAlloca(g.frame_info_type, NULL, "frame_info");
assert(al->isStaticAlloca());
static_assert(offsetof(FrameInfo, exc) == 0, "");
static_assert(offsetof(ExcInfo, type) == 0, "");
llvm::Value* exctype_gep
= builder.CreateConstInBoundsGEP2_32(builder.CreateConstInBoundsGEP2_32(al, 0, 0), 0, 0);
builder.CreateStore(embedConstantPtr(NULL, g.llvm_value_type_ptr), exctype_gep);
frame_info = al;
}
return frame_info;
}
ScopeInfo* IRGenState::getScopeInfo() {
return getSourceInfo()->getScopeInfo();
}
......@@ -575,6 +600,31 @@ private:
return boolFromI1(emitter, v);
}
case AST_LangPrimitive::SET_EXC_INFO: {
assert(node->args.size() == 3);
CompilerVariable* type = evalExpr(node->args[0], unw_info);
CompilerVariable* value = evalExpr(node->args[1], unw_info);
CompilerVariable* traceback = evalExpr(node->args[2], unw_info);
auto* builder = emitter.getBuilder();
llvm::Value* frame_info = irstate->getFrameInfoVar();
llvm::Value* exc_info = builder->CreateConstInBoundsGEP2_32(frame_info, 0, 0);
assert(exc_info->getType() == g.llvm_excinfo_type->getPointerTo());
ConcreteCompilerVariable* converted_type = type->makeConverted(emitter, UNKNOWN);
builder->CreateStore(converted_type->getValue(), builder->CreateConstInBoundsGEP2_32(exc_info, 0, 0));
converted_type->decvref(emitter);
ConcreteCompilerVariable* converted_value = value->makeConverted(emitter, UNKNOWN);
builder->CreateStore(converted_value->getValue(), builder->CreateConstInBoundsGEP2_32(exc_info, 0, 1));
converted_value->decvref(emitter);
ConcreteCompilerVariable* converted_traceback = traceback->makeConverted(emitter, UNKNOWN);
builder->CreateStore(converted_traceback->getValue(),
builder->CreateConstInBoundsGEP2_32(exc_info, 0, 2));
converted_traceback->decvref(emitter);
return getNone();
}
default:
RELEASE_ASSERT(0, "%d", node->opcode);
}
......@@ -2240,6 +2290,8 @@ public:
std::vector<llvm::Value*>& stackmap_args) override {
int initial_args = stackmap_args.size();
stackmap_args.push_back(irstate->getFrameInfoVar());
assert(INT->llvmType() == g.i64);
stackmap_args.push_back(getConstantInt((uint64_t)current_stmt, g.i64));
pp->addFrameVar("!current_stmt", INT);
......
......@@ -58,11 +58,13 @@ private:
llvm::MDNode* func_dbg_info;
llvm::AllocaInst* scratch_space;
llvm::Value* frame_info;
int scratch_size;
public:
IRGenState(CompiledFunction* cf, SourceInfo* source_info, GCBuilder* gc, llvm::MDNode* func_dbg_info)
: cf(cf), source_info(source_info), gc(gc), func_dbg_info(func_dbg_info), scratch_space(NULL), scratch_size(0) {
: cf(cf), source_info(source_info), gc(gc), func_dbg_info(func_dbg_info), scratch_space(NULL), frame_info(NULL),
scratch_size(0) {
assert(cf->func);
assert(!cf->clfunc); // in this case don't need to pass in sourceinfo
}
......@@ -76,6 +78,7 @@ public:
GCBuilder* getGC() { return gc; }
llvm::Value* getScratchSpace(int min_bytes);
llvm::Value* getFrameInfoVar();
ConcreteCompilerType* getReturnType() {
assert(cf->spec);
......
......@@ -63,6 +63,12 @@ int PatchpointInfo::patchpointSize() {
return CALL_ONLY_SIZE;
}
bool StackMap::Record::Location::operator==(const StackMap::Record::Location& rhs) {
// TODO: this check is overly-strict. Some fields are not used depending
// on the value of type, and I don't think "flags" is used at all currently.
return (type == rhs.type) && (flags == rhs.flags) && (regnum == rhs.regnum) && (offset == rhs.offset);
}
void PatchpointInfo::parseLocationMap(StackMap::Record* r, LocationMap* map) {
assert(r->locations.size() == totalStackmapArgs());
......@@ -70,6 +76,16 @@ void PatchpointInfo::parseLocationMap(StackMap::Record* r, LocationMap* map) {
// printf("parsing pp %ld:\n", reinterpret_cast<int64_t>(this));
StackMap::Record::Location frame_info_location = r->locations[cur_arg];
cur_arg++;
// We could allow the frame_info to exist in a different location for each callsite,
// but in reality it will always live at a fixed stack offset.
if (map->frameInfoFound()) {
assert(frame_info_location == map->frame_info_location);
} else {
map->frame_info_location = frame_info_location;
}
for (FrameVarInfo& frame_var : frame_vars) {
int num_args = frame_var.type->numFrameArgs();
......
......@@ -146,6 +146,9 @@ void initGlobalFuncs(GlobalState& g) {
g.llvm_excinfo_type = g.stdlib_module->getTypeByName("struct.pyston::ExcInfo");
assert(g.llvm_excinfo_type);
g.frame_info_type = g.stdlib_module->getTypeByName("struct.pyston::FrameInfo");
assert(g.frame_info_type);
#define GET(N) g.funcs.N = getFunc((void*)N, STRINGIFY(N))
g.funcs.printf = addFunc((void*)printf, g.i8_ptr, true);
......
......@@ -48,6 +48,8 @@ struct StackMap {
uint8_t flags;
uint16_t regnum;
int32_t offset;
bool operator==(const Location& rhs);
};
struct __attribute__((__packed__)) LiveOut {
......@@ -73,6 +75,10 @@ struct StackMap {
class LocationMap {
public:
std::vector<uint64_t> constants;
StackMap::Record::Location frame_info_location;
bool frameInfoFound() { return frame_info_location.type != 0; }
struct LocationTable {
struct LocationEntry {
uint64_t _debug_pp_id;
......
......@@ -236,6 +236,9 @@ public:
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::Direct) {
uint64_t reg_val = getReg(loc.regnum);
return reg_val + loc.offset;
} else if (loc.type == StackMap::Record::Location::LocationType::Indirect) {
uint64_t reg_val = getReg(loc.regnum);
uint64_t addr = reg_val + loc.offset;
......@@ -281,6 +284,19 @@ public:
abort();
}
FrameInfo* getFrameInfo() {
if (id.type == PythonFrameId::COMPILED) {
CompiledFunction* cf = getCF();
assert(cf->location_map->frameInfoFound());
const auto& frame_info_loc = cf->location_map->frame_info_location;
return reinterpret_cast<FrameInfo*>(readLocation(frame_info_loc));
} else if (id.type == PythonFrameId::INTERPRETED) {
return getFrameInfoForInterpretedFrame((void*)id.bp);
}
abort();
}
const PythonFrameId& getId() const { return id; }
static std::unique_ptr<PythonFrameIterator> end() { return std::unique_ptr<PythonFrameIterator>(nullptr); }
......@@ -450,6 +466,37 @@ const LineInfo* getMostRecentLineInfo() {
return lineInfoForFrame(*frame);
}
ExcInfo getFrameExcInfo() {
std::vector<ExcInfo*> to_update;
ExcInfo* cur_exc = NULL;
for (PythonFrameIterator& frame_iter : unwindPythonFrames()) {
FrameInfo* frame_info = frame_iter.getFrameInfo();
cur_exc = &frame_info->exc;
if (!cur_exc->type) {
to_update.push_back(cur_exc);
continue;
}
break;
}
assert(cur_exc); // Only way this could still be NULL is if there weren't any python frames
if (!cur_exc->type) {
// No exceptions found:
*cur_exc = ExcInfo(None, None, None);
}
assert(cur_exc->value);
assert(cur_exc->traceback);
for (auto* ex : to_update) {
*ex = *cur_exc;
}
return *cur_exc;
}
CompiledFunction* getTopCompiledFunction() {
return getTopPythonFrame()->getCF();
}
......@@ -460,13 +507,6 @@ BoxedModule* getCurrentModule() {
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) {
for (PythonFrameIterator& frame_info : unwindPythonFrames()) {
if (frame_info.getId().type == PythonFrameId::COMPILED) {
......
......@@ -30,11 +30,8 @@ CompiledFunction* getCFForAddress(uint64_t addr);
class BoxedDict;
BoxedDict* getLocals(bool only_user_visible);
struct ExecutionPoint {
CompiledFunction* cf;
AST_stmt* current_stmt;
};
ExecutionPoint getExecutionPoint();
// Fetches the frame-local excinfo object, calculating it if necessary (from previous frames):
ExcInfo getFrameExcInfo();
}
#endif
......@@ -1455,6 +1455,9 @@ bool PrintVisitor::visit_langprimitive(AST_LangPrimitive* node) {
case AST_LangPrimitive::NONZERO:
printf("NONZERO");
break;
case AST_LangPrimitive::SET_EXC_INFO:
printf("SET_EXC_INFO");
break;
default:
RELEASE_ASSERT(0, "%d", node->opcode);
}
......
......@@ -977,6 +977,7 @@ public:
IMPORT_STAR,
NONE,
NONZERO,
SET_EXC_INFO,
} opcode;
std::vector<AST_expr*> args;
......
......@@ -527,6 +527,13 @@ private:
made->col_offset = orig->col_offset;
made->lineno = orig->lineno;
return made;
} else if (val->type == AST_TYPE::Index) {
AST_Index* orig = ast_cast<AST_Index>(val);
AST_Index* made = new AST_Index();
made->value = _dup(orig->value);
made->col_offset = orig->col_offset;
made->lineno = orig->lineno;
return made;
} else {
RELEASE_ASSERT(0, "%d", val->type);
}
......@@ -968,6 +975,8 @@ private:
rtn = remapIfExp(ast_cast<AST_IfExp>(node));
break;
case AST_TYPE::Index:
if (ast_cast<AST_Index>(node)->value->type == AST_TYPE::Num)
return node;
rtn = remapIndex(ast_cast<AST_Index>(node));
break;
case AST_TYPE::Lambda:
......@@ -1851,7 +1860,7 @@ public:
cfg->placeBlock(exc_handler_block);
curblock = exc_handler_block;
// TODO: this should be an EXCEPTION_MATCHES(exc_type_name)
// TODO This is supposed to be exc_type_name (value doesn't matter for checking matches)
AST_expr* exc_obj = makeName(exc_value_name, AST_TYPE::Load, node->lineno);
bool caught_all = false;
......@@ -1862,6 +1871,7 @@ public:
if (exc_handler->type) {
AST_expr* handled_type = remapExpr(exc_handler->type);
// TODO: this should be an EXCEPTION_MATCHES(exc_type_name)
AST_LangPrimitive* is_caught_here = new AST_LangPrimitive(AST_LangPrimitive::ISINSTANCE);
is_caught_here->args.push_back(_dup(exc_obj));
is_caught_here->args.push_back(handled_type);
......@@ -1883,6 +1893,12 @@ public:
caught_all = true;
}
AST_LangPrimitive* set_exc_info = new AST_LangPrimitive(AST_LangPrimitive::SET_EXC_INFO);
set_exc_info->args.push_back(makeName(exc_type_name, AST_TYPE::Load, node->lineno));
set_exc_info->args.push_back(makeName(exc_value_name, AST_TYPE::Load, node->lineno));
set_exc_info->args.push_back(makeName(exc_traceback_name, AST_TYPE::Load, node->lineno));
push_back(makeExpr(set_exc_info));
if (exc_handler->name) {
pushAssign(exc_handler->name, _dup(exc_obj));
}
......
......@@ -476,6 +476,16 @@ struct ExcInfo {
ExcInfo(Box* type, Box* value, Box* traceback) : type(type), value(value), traceback(traceback) {}
bool matches(BoxedClass* cls) const;
};
struct FrameInfo {
// *Not the same semantics as CPython's frame->f_exc*
// In CPython, f_exc is the saved exc_info from the previous frame.
// In Pyston, exc is the frame-local value of sys.exc_info.
// - This makes frame entering+leaving faster at the expense of slower exceptions.
ExcInfo exc;
FrameInfo(ExcInfo exc) : exc(exc) {}
};
}
#endif
......@@ -688,13 +688,6 @@ 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);
}
......@@ -1054,7 +1047,6 @@ 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)));
......
......@@ -19,6 +19,7 @@
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "codegen/unwinding.h"
#include "core/types.h"
#include "gc/collector.h"
#include "runtime/inline/boxing.h"
......@@ -32,9 +33,11 @@ BoxedModule* sys_module;
BoxedDict* sys_modules_dict;
Box* sysExcInfo() {
return new BoxedTuple({ cur_thread_state.curexc_type ? cur_thread_state.curexc_type : None,
cur_thread_state.curexc_value ? cur_thread_state.curexc_value : None,
cur_thread_state.curexc_traceback ? cur_thread_state.curexc_traceback : None });
ExcInfo exc = getFrameExcInfo();
assert(exc.type);
assert(exc.value);
assert(exc.traceback);
return new BoxedTuple({ exc.type, exc.value, exc.traceback });
}
static Box* sysExit(Box* arg) {
......
......@@ -100,7 +100,7 @@ Box* generatorThrow(Box* s, BoxedClass* e) {
assert(isSubclass(e, Exception));
BoxedGenerator* self = static_cast<BoxedGenerator*>(s);
Box* ex = exceptionNew1(e);
self->exception = ExcInfo(ex->cls, ex, NULL);
self->exception = ExcInfo(ex->cls, ex, None);
return generatorSend(self, None);
}
......
......@@ -35,13 +35,11 @@ static void forceLink(void* x) {
printf("%p\n", x);
}
extern "C" void __py_personality_v0() {
RELEASE_ASSERT(0, "not used");
}
namespace _force {
// Force the "FrameInfo" type to make it into the stdlib:
FrameInfo* _frame_info_forcer;
#define FORCE(name) forceLink((void*)name)
void force() {
FORCE(softspace);
......
......@@ -100,6 +100,11 @@ static std::vector<const LineInfo*> last_tb;
void raiseRaw(const ExcInfo& e) __attribute__((__noreturn__));
void raiseRaw(const ExcInfo& e) {
// Should set these to None before getting here:
assert(e.type);
assert(e.value);
assert(e.traceback);
// Using libgcc:
throw e;
......@@ -112,7 +117,7 @@ void raiseExc(Box* exc_obj) {
last_tb = std::move(entries);
last_exc = exc_obj;
raiseRaw(ExcInfo(exc_obj->cls, exc_obj, NULL));
raiseRaw(ExcInfo(exc_obj->cls, exc_obj, None));
}
// Have a special helper function for syntax errors, since we want to include the location
......@@ -125,7 +130,7 @@ void raiseSyntaxError(const char* msg, int lineno, int col_offset, const std::st
// TODO: leaks this!
last_tb.push_back(new LineInfo(lineno, col_offset, file, func));
raiseRaw(ExcInfo(SyntaxError, last_exc, NULL));
raiseRaw(ExcInfo(SyntaxError, last_exc, None));
}
static void _printTraceback(const std::vector<const LineInfo*>& tb) {
......@@ -216,7 +221,7 @@ extern "C" void exit(int code) {
}
void raise0() {
raiseRaw(ExcInfo(last_exc->cls, last_exc, NULL));
raiseRaw(ExcInfo(last_exc->cls, last_exc, None));
}
bool ExcInfo::matches(BoxedClass* cls) const {
......
......@@ -44,4 +44,7 @@ def f2():
f2()
print f(4, 2)
print f(4.1, 2.3)
try:
print f(4.1, 2.3)
except TypeError, e:
print e
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