Commit 962471b7 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Add extra cxx-exception blocks

to explicitly represent exceptional control flow, so that we can put refcounting
operations on it.
parent 3e6f2e41
...@@ -627,6 +627,7 @@ static ConcreteCompilerVariable* _call(IREmitter& emitter, const OpInfo& info, l ...@@ -627,6 +627,7 @@ static ConcreteCompilerVariable* _call(IREmitter& emitter, const OpInfo& info, l
assert(llvm::cast<llvm::FunctionType>(llvm::cast<llvm::PointerType>(func->getType())->getElementType()) assert(llvm::cast<llvm::FunctionType>(llvm::cast<llvm::PointerType>(func->getType())->getElementType())
->getReturnType() == g.llvm_value_type_ptr); ->getReturnType() == g.llvm_value_type_ptr);
rtn = emitter.getBuilder()->CreateIntToPtr(uncasted, g.llvm_value_type_ptr); rtn = emitter.getBuilder()->CreateIntToPtr(uncasted, g.llvm_value_type_ptr);
emitter.setType(rtn, RefType::OWNED);
} else { } else {
// printf("\n"); // printf("\n");
// func->dump(); // func->dump();
...@@ -637,6 +638,7 @@ static ConcreteCompilerVariable* _call(IREmitter& emitter, const OpInfo& info, l ...@@ -637,6 +638,7 @@ static ConcreteCompilerVariable* _call(IREmitter& emitter, const OpInfo& info, l
// printf("%ld %ld\n", llvm_args.size(), args.size()); // printf("%ld %ld\n", llvm_args.size(), args.size());
// printf("\n"); // printf("\n");
rtn = emitter.createCall(info.unw_info, func, llvm_args, target_exception_style); rtn = emitter.createCall(info.unw_info, func, llvm_args, target_exception_style);
emitter.setType(rtn, RefType::OWNED);
} }
assert(rtn->getType() == rtn_type->llvmType()); assert(rtn->getType() == rtn_type->llvmType());
......
...@@ -107,7 +107,7 @@ public: ...@@ -107,7 +107,7 @@ public:
virtual BORROWED(Box*) getIntConstant(int64_t n) = 0; virtual BORROWED(Box*) getIntConstant(int64_t n) = 0;
virtual BORROWED(Box*) getFloatConstant(double d) = 0; virtual BORROWED(Box*) getFloatConstant(double d) = 0;
virtual void setType(llvm::Value* v, RefType reftype) = 0; virtual llvm::Value* setType(llvm::Value* v, RefType reftype) = 0;
virtual ConcreteCompilerVariable* getNone() = 0; virtual ConcreteCompilerVariable* getNone() = 0;
}; };
......
...@@ -257,6 +257,7 @@ llvm::Value* IRGenState::getGlobals() { ...@@ -257,6 +257,7 @@ llvm::Value* IRGenState::getGlobals() {
if (!globals) { if (!globals) {
assert(source_info->scoping->areGlobalsFromModule()); assert(source_info->scoping->areGlobalsFromModule());
this->globals = embedRelocatablePtr(source_info->parent_module, g.llvm_value_type_ptr); this->globals = embedRelocatablePtr(source_info->parent_module, g.llvm_value_type_ptr);
this->getRefcounts()->setType(this->globals, RefType::BORROWED);
} }
return this->globals; return this->globals;
} }
...@@ -276,7 +277,12 @@ private: ...@@ -276,7 +277,12 @@ private:
llvm::CallSite emitCall(const UnwindInfo& unw_info, llvm::Value* callee, const std::vector<llvm::Value*>& args, llvm::CallSite emitCall(const UnwindInfo& unw_info, llvm::Value* callee, const std::vector<llvm::Value*>& args,
ExceptionStyle target_exception_style) { ExceptionStyle target_exception_style) {
if (target_exception_style == CXX && (unw_info.hasHandler() || irstate->getExceptionStyle() == CAPI)) { bool needs_refcounting_fixup = true;
bool needs_cxx_interception
= (target_exception_style == CXX
&& (needs_refcounting_fixup || unw_info.hasHandler() || irstate->getExceptionStyle() == CAPI));
if (needs_cxx_interception) {
// Create the invoke: // Create the invoke:
llvm::BasicBlock* normal_dest llvm::BasicBlock* normal_dest
= llvm::BasicBlock::Create(g.context, curblock->getName(), irstate->getLLVMFunction()); = llvm::BasicBlock::Create(g.context, curblock->getName(), irstate->getLLVMFunction());
...@@ -285,8 +291,6 @@ private: ...@@ -285,8 +291,6 @@ private:
if (unw_info.hasHandler()) { if (unw_info.hasHandler()) {
final_exc_dest = unw_info.exc_dest; final_exc_dest = unw_info.exc_dest;
} else { } else {
assert(irstate->getExceptionStyle() == CAPI && "shoudn't have bothered creating an invoke");
final_exc_dest = NULL; // signal to reraise as a capi exception final_exc_dest = NULL; // signal to reraise as a capi exception
} }
...@@ -503,8 +507,9 @@ public: ...@@ -503,8 +507,9 @@ public:
return autoDecref(irstate->getSourceInfo()->parent_module->getFloatConstant(d)); return autoDecref(irstate->getSourceInfo()->parent_module->getFloatConstant(d));
} }
void setType(llvm::Value* v, RefType reftype) { llvm::Value* setType(llvm::Value* v, RefType reftype) {
irstate->getRefcounts()->setType(v, reftype); irstate->getRefcounts()->setType(v, reftype);
return v;
} }
ConcreteCompilerVariable* getNone() { ConcreteCompilerVariable* getNone() {
...@@ -574,7 +579,7 @@ private: ...@@ -574,7 +579,7 @@ private:
llvm::SmallVector<ExceptionState, 2> incoming_exc_state; llvm::SmallVector<ExceptionState, 2> incoming_exc_state;
// These are the values that are outgoing of an invoke block: // These are the values that are outgoing of an invoke block:
llvm::SmallVector<ExceptionState, 2> outgoing_exc_state; llvm::SmallVector<ExceptionState, 2> outgoing_exc_state;
llvm::DenseMap<llvm::BasicBlock*, llvm::BasicBlock*> cxx_exc_dests; //llvm::DenseMap<llvm::BasicBlock*, llvm::BasicBlock*> cxx_exc_dests;
llvm::DenseMap<llvm::BasicBlock*, llvm::BasicBlock*> capi_exc_dests; llvm::DenseMap<llvm::BasicBlock*, llvm::BasicBlock*> capi_exc_dests;
llvm::DenseMap<llvm::BasicBlock*, llvm::PHINode*> capi_phis; llvm::DenseMap<llvm::BasicBlock*, llvm::PHINode*> capi_phis;
...@@ -1078,14 +1083,17 @@ private: ...@@ -1078,14 +1083,17 @@ private:
std::vector<llvm::Value*> llvm_args; std::vector<llvm::Value*> llvm_args;
llvm_args.push_back(irstate->getGlobals()); llvm_args.push_back(irstate->getGlobals());
llvm_args.push_back(embedRelocatablePtr(node->id.getBox(), g.llvm_boxedstring_type_ptr)); llvm_args.push_back(emitter.setType(embedRelocatablePtr(node->id.getBox(), g.llvm_boxedstring_type_ptr),
RefType::BORROWED));
llvm::Value* uncasted = emitter.createIC(pp, (void*)pyston::getGlobal, llvm_args, unw_info); llvm::Value* uncasted = emitter.createIC(pp, (void*)pyston::getGlobal, llvm_args, unw_info);
llvm::Value* r = emitter.getBuilder()->CreateIntToPtr(uncasted, g.llvm_value_type_ptr); llvm::Value* r = emitter.getBuilder()->CreateIntToPtr(uncasted, g.llvm_value_type_ptr);
emitter.setType(r, RefType::OWNED);
return new ConcreteCompilerVariable(UNKNOWN, r); return new ConcreteCompilerVariable(UNKNOWN, r);
} else { } else {
llvm::Value* r = emitter.createCall2(unw_info, g.funcs.getGlobal, irstate->getGlobals(), llvm::Value* r = emitter.createCall2(unw_info, g.funcs.getGlobal, irstate->getGlobals(),
embedRelocatablePtr(node->id.getBox(), g.llvm_boxedstring_type_ptr)); embedRelocatablePtr(node->id.getBox(), g.llvm_boxedstring_type_ptr));
emitter.setType(r, RefType::OWNED);
return new ConcreteCompilerVariable(UNKNOWN, r); return new ConcreteCompilerVariable(UNKNOWN, r);
} }
} }
...@@ -1921,7 +1929,7 @@ private: ...@@ -1921,7 +1929,7 @@ private:
auto d = evalExpr(node->dest, unw_info); auto d = evalExpr(node->dest, unw_info);
dest = d->makeConverted(emitter, d->getBoxType()); dest = d->makeConverted(emitter, d->getBoxType());
} else { } else {
llvm::Value* sys_stdout_val = emitter.createCall(unw_info, g.funcs.getSysStdout); llvm::Value* sys_stdout_val = emitter.createCall(unw_info, g.funcs.getSysStdout, NOEXC);
emitter.setType(sys_stdout_val, RefType::BORROWED); emitter.setType(sys_stdout_val, RefType::BORROWED);
dest = new ConcreteCompilerVariable(UNKNOWN, sys_stdout_val); dest = new ConcreteCompilerVariable(UNKNOWN, sys_stdout_val);
// TODO: speculate that sys.stdout is a file? // TODO: speculate that sys.stdout is a file?
...@@ -2673,7 +2681,7 @@ public: ...@@ -2673,7 +2681,7 @@ public:
void doSafePoint(AST_stmt* next_statement) override { void doSafePoint(AST_stmt* next_statement) override {
// Unwind info is always needed in allowGLReadPreemption if it has any chance of // Unwind info is always needed in allowGLReadPreemption if it has any chance of
// running arbitrary code like finalizers. // running arbitrary code like finalizers.
emitter.createCall(UnwindInfo(next_statement, NULL), g.funcs.allowGLReadPreemption); emitter.createCall(UnwindInfo(next_statement, NULL), g.funcs.allowGLReadPreemption, NOEXC);
} }
// Create a (or reuse an existing) block that will catch a CAPI exception, and then forward // Create a (or reuse an existing) block that will catch a CAPI exception, and then forward
...@@ -2683,6 +2691,7 @@ public: ...@@ -2683,6 +2691,7 @@ public:
// instead propagate the exception out of the function. // instead propagate the exception out of the function.
llvm::BasicBlock* getCAPIExcDest(llvm::BasicBlock* from_block, llvm::BasicBlock* final_dest, llvm::BasicBlock* getCAPIExcDest(llvm::BasicBlock* from_block, llvm::BasicBlock* final_dest,
AST_stmt* current_stmt) override { AST_stmt* current_stmt) override {
assert(0 && "check refcounting");
llvm::BasicBlock*& capi_exc_dest = capi_exc_dests[final_dest]; llvm::BasicBlock*& capi_exc_dest = capi_exc_dests[final_dest];
llvm::PHINode*& phi_node = capi_phis[final_dest]; llvm::PHINode*& phi_node = capi_phis[final_dest];
...@@ -2745,13 +2754,13 @@ public: ...@@ -2745,13 +2754,13 @@ public:
} }
llvm::BasicBlock* getCXXExcDest(llvm::BasicBlock* final_dest) override { llvm::BasicBlock* getCXXExcDest(llvm::BasicBlock* final_dest) override {
llvm::BasicBlock*& cxx_exc_dest = cxx_exc_dests[final_dest]; //llvm::BasicBlock*& cxx_exc_dest = cxx_exc_dests[final_dest];
if (cxx_exc_dest) //if (cxx_exc_dest)
return cxx_exc_dest; //return cxx_exc_dest;
llvm::BasicBlock* orig_block = curblock; llvm::BasicBlock* orig_block = curblock;
cxx_exc_dest = llvm::BasicBlock::Create(g.context, "", irstate->getLLVMFunction()); llvm::BasicBlock* cxx_exc_dest = llvm::BasicBlock::Create(g.context, "", irstate->getLLVMFunction());
emitter.getBuilder()->SetInsertPoint(cxx_exc_dest); emitter.getBuilder()->SetInsertPoint(cxx_exc_dest);
...@@ -2780,7 +2789,11 @@ public: ...@@ -2780,7 +2789,11 @@ public:
llvm::Value* exc_value = builder->CreateLoad(builder->CreateConstInBoundsGEP2_32(excinfo_pointer_casted, 0, 1)); llvm::Value* exc_value = builder->CreateLoad(builder->CreateConstInBoundsGEP2_32(excinfo_pointer_casted, 0, 1));
llvm::Value* exc_traceback llvm::Value* exc_traceback
= builder->CreateLoad(builder->CreateConstInBoundsGEP2_32(excinfo_pointer_casted, 0, 2)); = builder->CreateLoad(builder->CreateConstInBoundsGEP2_32(excinfo_pointer_casted, 0, 2));
emitter.setType(exc_type, RefType::OWNED);
emitter.setType(exc_value, RefType::OWNED);
emitter.setType(exc_traceback, RefType::OWNED);
// final_dest==NULL => propagate the exception out of the function.
if (final_dest) { if (final_dest) {
// Catch the exception and forward to final_dest: // Catch the exception and forward to final_dest:
addOutgoingExceptionState(ExceptionState(cxx_exc_dest, addOutgoingExceptionState(ExceptionState(cxx_exc_dest,
...@@ -2789,13 +2802,19 @@ public: ...@@ -2789,13 +2802,19 @@ public:
new ConcreteCompilerVariable(UNKNOWN, exc_traceback))); new ConcreteCompilerVariable(UNKNOWN, exc_traceback)));
builder->CreateBr(final_dest); builder->CreateBr(final_dest);
} else { } else if (irstate->getExceptionStyle() == CAPI) {
// Propagate the exception out of the function. auto call_inst = builder->CreateCall3(g.funcs.PyErr_Restore, exc_type, exc_value, exc_traceback);
// We shouldn't be hitting this case if the current function is CXX-style; then we should have irstate->getRefcounts()->refConsumed(exc_type, call_inst);
// just not created an Invoke and let the exception machinery propagate it for us. irstate->getRefcounts()->refConsumed(exc_value, call_inst);
assert(irstate->getExceptionStyle() == CAPI); irstate->getRefcounts()->refConsumed(exc_traceback, call_inst);
builder->CreateCall3(g.funcs.PyErr_Restore, exc_type, exc_value, exc_traceback);
builder->CreateRet(getNullPtr(g.llvm_value_type_ptr)); builder->CreateRet(getNullPtr(g.llvm_value_type_ptr));
} else {
auto call_inst = emitter.getBuilder()->CreateCall3(g.funcs.rawThrow, exc_type, exc_value, exc_traceback);
irstate->getRefcounts()->refConsumed(exc_type, call_inst);
irstate->getRefcounts()->refConsumed(exc_value, call_inst);
irstate->getRefcounts()->refConsumed(exc_traceback, call_inst);
builder->CreateUnreachable();
} }
emitter.setCurrentBasicBlock(orig_block); emitter.setCurrentBasicBlock(orig_block);
......
...@@ -109,6 +109,7 @@ void RefcountTracker::addRefcounts(IRGenState* irstate) { ...@@ -109,6 +109,7 @@ void RefcountTracker::addRefcounts(IRGenState* irstate) {
if (rt->vars.count(v) == 0) { if (rt->vars.count(v) == 0) {
num_untracked++; num_untracked++;
printf("missed a refcounted object: "); printf("missed a refcounted object: ");
fflush(stdout);
v->dump(); v->dump();
//abort(); //abort();
} }
......
...@@ -315,6 +315,7 @@ void initGlobalFuncs(GlobalState& g) { ...@@ -315,6 +315,7 @@ void initGlobalFuncs(GlobalState& g) {
GET(raise0_capi); GET(raise0_capi);
GET(raise3); GET(raise3);
GET(raise3_capi); GET(raise3_capi);
GET(rawThrow);
GET(PyErr_Fetch); GET(PyErr_Fetch);
GET(PyErr_NormalizeException); GET(PyErr_NormalizeException);
GET(PyErr_Restore); GET(PyErr_Restore);
......
...@@ -50,7 +50,7 @@ struct GlobalFuncs { ...@@ -50,7 +50,7 @@ struct GlobalFuncs {
llvm::Value* boxedLocalsSet, *boxedLocalsGet, *boxedLocalsDel; llvm::Value* boxedLocalsSet, *boxedLocalsGet, *boxedLocalsDel;
llvm::Value* __cxa_end_catch; llvm::Value* __cxa_end_catch;
llvm::Value* raise0, *raise0_capi, *raise3, *raise3_capi; llvm::Value* raise0, *raise0_capi, *raise3, *raise3_capi, *rawThrow;
llvm::Value* PyErr_Fetch, *PyErr_NormalizeException, *PyErr_Restore, *caughtCapiException, *reraiseCapiExcAsCxx; llvm::Value* PyErr_Fetch, *PyErr_NormalizeException, *PyErr_Restore, *caughtCapiException, *reraiseCapiExcAsCxx;
llvm::Value* deopt; llvm::Value* deopt;
......
...@@ -55,9 +55,12 @@ enum class EffortLevel { ...@@ -55,9 +55,12 @@ enum class EffortLevel {
// determine when to emit code in one style or the other. // determine when to emit code in one style or the other.
// Many runtime functions support being called in either style, and can get passed one of these enum values // Many runtime functions support being called in either style, and can get passed one of these enum values
// as a template parameter to switch between them. // as a template parameter to switch between them.
// "NOEXC" is a special exception style that says that no exception (of either type) will get thrown.
enum ExceptionStyle { enum ExceptionStyle {
CAPI, CAPI,
CXX, CXX,
NOEXC,
}; };
// Much of our runtime supports "rewriting" aka tracing itself. Our tracing JIT requires support from the // Much of our runtime supports "rewriting" aka tracing itself. Our tracing JIT requires support from the
......
...@@ -275,6 +275,10 @@ extern "C" void reraiseCapiExcAsCxx() { ...@@ -275,6 +275,10 @@ extern "C" void reraiseCapiExcAsCxx() {
throw e; throw e;
} }
extern "C" void rawThrow(Box* type, Box* value, Box* tb) {
throw ExcInfo(type, value, tb);
}
void caughtCxxException(LineInfo line_info, ExcInfo* exc_info) { void caughtCxxException(LineInfo line_info, ExcInfo* exc_info) {
static StatCounter frames_unwound("num_frames_unwound_python"); static StatCounter frames_unwound("num_frames_unwound_python");
frames_unwound.log(); frames_unwound.log();
......
...@@ -129,6 +129,7 @@ void force() { ...@@ -129,6 +129,7 @@ void force() {
FORCE(raise0_capi); FORCE(raise0_capi);
FORCE(raise3); FORCE(raise3);
FORCE(raise3_capi); FORCE(raise3_capi);
FORCE(rawThrow);
FORCE(PyErr_Fetch); FORCE(PyErr_Fetch);
FORCE(PyErr_NormalizeException); FORCE(PyErr_NormalizeException);
FORCE(PyErr_Restore); FORCE(PyErr_Restore);
......
...@@ -37,6 +37,7 @@ extern "C" void raise0(ExcInfo* frame_exc_info) __attribute__((__noreturn__)); ...@@ -37,6 +37,7 @@ extern "C" void raise0(ExcInfo* frame_exc_info) __attribute__((__noreturn__));
extern "C" void raise0_capi(ExcInfo* frame_exc_info) noexcept; extern "C" void raise0_capi(ExcInfo* frame_exc_info) noexcept;
extern "C" void raise3(Box*, Box*, Box*) __attribute__((__noreturn__)); extern "C" void raise3(Box*, Box*, Box*) __attribute__((__noreturn__));
extern "C" void raise3_capi(Box*, Box*, Box*) noexcept; extern "C" void raise3_capi(Box*, Box*, Box*) noexcept;
extern "C" void rawThrow(Box*, Box*, Box*) __attribute__((__noreturn__));
void raiseExc(STOLEN(Box*) exc_obj) __attribute__((__noreturn__)); void raiseExc(STOLEN(Box*) exc_obj) __attribute__((__noreturn__));
void _printStacktrace(); void _printStacktrace();
......
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