diff --git a/Makefile b/Makefile index 515915067..964327dcd 100644 --- a/Makefile +++ b/Makefile @@ -1229,7 +1229,7 @@ endif # depend on the first one. $(firstword $(TEST_EXT_MODULE_OBJS)): $(TEST_EXT_MODULE_SRCS) | $(BUILD_PY) $(VERB) cd $(TEST_DIR)/test_extension; time ../../$(BUILD_PY) setup.py build - $(VERB) cd $(TEST_DIR)/test_extension; ln -sf $(TEST_EXT_MODULE_NAMES:%=build/lib.linux2-2.7/%.pyston.so) . + $(VERB) cd $(TEST_DIR)/test_extension; ln -sf $(TEST_EXT_MODULE_NAMES:%=build/lib.linux-x86_64-2.7/%.pyston.so) . $(VERB) touch -c $(TEST_EXT_MODULE_OBJS) $(wordlist 2,9999,$(TEST_EXT_MODULE_OBJS)): $(firstword $(TEST_EXT_MODULE_OBJS)) $(firstword $(SHAREDMODS_OBJS)): $(SHAREDMODS_SRCS) | $(BUILD_PY) diff --git a/src/codegen/compvars.cpp b/src/codegen/compvars.cpp index f66d47117..3b7bc1471 100644 --- a/src/codegen/compvars.cpp +++ b/src/codegen/compvars.cpp @@ -489,14 +489,24 @@ CompilerVariable* UnknownType::getattr(IREmitter& emitter, const OpInfo& info, C llvm::Value* rtn_val = NULL; + ExceptionStyle target_exception_style = CXX; + if (info.unw_info.capi_exc_dest) + target_exception_style = CAPI; + llvm::Value* llvm_func; void* raw_func; if (cls_only) { + assert(target_exception_style == CXX); llvm_func = g.funcs.getclsattr; raw_func = (void*)pyston::getclsattr; } else { - llvm_func = g.funcs.getattr; - raw_func = (void*)pyston::getattr; + if (target_exception_style == CXX) { + llvm_func = g.funcs.getattr; + raw_func = (void*)pyston::getattr; + } else { + llvm_func = g.funcs.getattr_capi; + raw_func = (void*)pyston::getattr_capi; + } } bool do_patchpoint = ENABLE_ICGETATTRS; @@ -507,15 +517,20 @@ CompilerVariable* UnknownType::getattr(IREmitter& emitter, const OpInfo& info, C llvm_args.push_back(var->getValue()); llvm_args.push_back(ptr); - llvm::Value* uncasted = emitter.createIC(pp, raw_func, llvm_args, info.unw_info); + llvm::Value* uncasted = emitter.createIC(pp, raw_func, llvm_args, info.unw_info, target_exception_style); rtn_val = emitter.getBuilder()->CreateIntToPtr(uncasted, g.llvm_value_type_ptr); } else { - rtn_val = emitter.createCall2(info.unw_info, llvm_func, var->getValue(), ptr); + rtn_val = emitter.createCall2(info.unw_info, llvm_func, var->getValue(), ptr, target_exception_style); } + + if (target_exception_style == CAPI) + emitter.checkAndPropagateCapiException(info.unw_info, rtn_val, getNullPtr(g.llvm_value_type_ptr)); + return new ConcreteCompilerVariable(UNKNOWN, rtn_val, true); } -static ConcreteCompilerVariable* _call(IREmitter& emitter, const OpInfo& info, llvm::Value* func, void* func_addr, +static ConcreteCompilerVariable* _call(IREmitter& emitter, const OpInfo& info, llvm::Value* func, + ExceptionStyle target_exception_style, void* func_addr, const std::vector& other_args, ArgPassSpec argspec, const std::vector& args, const std::vector* keyword_names, ConcreteCompilerType* rtn_type) { @@ -551,7 +566,6 @@ static ConcreteCompilerVariable* _call(IREmitter& emitter, const OpInfo& info, l llvm_args.push_back(getNullPtr(g.llvm_value_type_ptr)); } - llvm::Value* mallocsave = NULL; if (args.size() >= 4) { llvm::Value* arg_array; @@ -594,7 +608,7 @@ static ConcreteCompilerVariable* _call(IREmitter& emitter, const OpInfo& info, l ICSetupInfo* pp = createCallsiteIC(info.getTypeRecorder(), args.size()); - llvm::Value* uncasted = emitter.createIC(pp, func_addr, llvm_args, info.unw_info); + llvm::Value* uncasted = emitter.createIC(pp, func_addr, llvm_args, info.unw_info, target_exception_style); assert(llvm::cast(llvm::cast(func->getType())->getElementType()) ->getReturnType() == g.llvm_value_type_ptr); @@ -608,13 +622,7 @@ static ConcreteCompilerVariable* _call(IREmitter& emitter, const OpInfo& info, l //} // printf("%ld %ld\n", llvm_args.size(), args.size()); // printf("\n"); - rtn = emitter.createCall(info.unw_info, func, llvm_args); - } - - if (mallocsave) { - llvm::Value* l_free = embedConstantPtr( - (void*)free, llvm::FunctionType::get(g.void_, g.i8->getPointerTo(), false)->getPointerTo()); - emitter.getBuilder()->CreateCall(l_free, mallocsave); + rtn = emitter.createCall(info.unw_info, func, llvm_args, target_exception_style); } for (int i = 0; i < args.size(); i++) { @@ -622,6 +630,11 @@ static ConcreteCompilerVariable* _call(IREmitter& emitter, const OpInfo& info, l } assert(rtn->getType() == rtn_type->llvmType()); + + if (target_exception_style == CAPI) { + emitter.checkAndPropagateCapiException(info.unw_info, rtn, getNullPtr(g.llvm_value_type_ptr)); + } + return new ConcreteCompilerVariable(rtn_type, rtn, true); } @@ -650,7 +663,7 @@ CompilerVariable* UnknownType::call(IREmitter& emitter, const OpInfo& info, Conc llvm::Value* llvm_argspec = llvm::ConstantInt::get(g.i32, argspec.asInt(), false); other_args.push_back(llvm_argspec); - return _call(emitter, info, func, (void*)runtimeCall, other_args, argspec, args, keyword_names, UNKNOWN); + return _call(emitter, info, func, CXX, (void*)runtimeCall, other_args, argspec, args, keyword_names, UNKNOWN); } CompilerVariable* UnknownType::callattr(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var, @@ -678,7 +691,8 @@ CompilerVariable* UnknownType::callattr(IREmitter& emitter, const OpInfo& info, other_args.push_back(var->getValue()); other_args.push_back(embedRelocatablePtr(attr, g.llvm_boxedstring_type_ptr)); other_args.push_back(getConstantInt(flags.asInt(), g.i64)); - return _call(emitter, info, func, (void*)pyston::callattr, other_args, flags.argspec, args, keyword_names, UNKNOWN); + return _call(emitter, info, func, CXX, (void*)pyston::callattr, other_args, flags.argspec, args, keyword_names, + UNKNOWN); } ConcreteCompilerVariable* UnknownType::nonzero(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var) { @@ -1480,10 +1494,18 @@ class NormalObjectType : public ConcreteCompilerType { if (canStaticallyResolveGetattrs()) { Box* rtattr = typeLookup(cls, attr, nullptr); if (rtattr == NULL) { + ExceptionStyle exception_style = info.unw_info.capi_exc_dest ? CAPI : CXX; + llvm::Value* raise_func = exception_style == CXX ? g.funcs.raiseAttributeErrorStr + : g.funcs.raiseAttributeErrorStrCapi; llvm::CallSite call = emitter.createCall3( - info.unw_info, g.funcs.raiseAttributeErrorStr, embedRelocatablePtr(cls->tp_name, g.i8_ptr), - embedRelocatablePtr(attr->data(), g.i8_ptr), getConstantInt(attr->size(), g.i64)); - call.setDoesNotReturn(); + info.unw_info, raise_func, embedRelocatablePtr(cls->tp_name, g.i8_ptr), + embedRelocatablePtr(attr->data(), g.i8_ptr), getConstantInt(attr->size(), g.i64), exception_style); + if (exception_style == CAPI) { + emitter.checkAndPropagateCapiException(info.unw_info, getNullPtr(g.llvm_value_type_ptr), + getNullPtr(g.llvm_value_type_ptr)); + } else { + call.setDoesNotReturn(); + } return undefVariable(); } @@ -1623,8 +1645,8 @@ class NormalObjectType : public ConcreteCompilerType { std::vector other_args; - ConcreteCompilerVariable* rtn = _call(emitter, info, linked_function, cf->code, other_args, argspec, new_args, - keyword_names, cf->spec->rtn_type); + ConcreteCompilerVariable* rtn = _call(emitter, info, linked_function, cf->exception_style, cf->code, other_args, + argspec, new_args, keyword_names, cf->spec->rtn_type); assert(rtn->getType() == cf->spec->rtn_type); assert(rtn->getType() != UNDEF); diff --git a/src/codegen/irgen.h b/src/codegen/irgen.h index c3fb56d3c..28769527a 100644 --- a/src/codegen/irgen.h +++ b/src/codegen/irgen.h @@ -32,16 +32,19 @@ class IREmitter; struct UnwindInfo { public: AST_stmt* current_stmt; - llvm::BasicBlock* exc_dest; - bool needsInvoke() { return exc_dest != NULL; } + llvm::BasicBlock* capi_exc_dest; + llvm::BasicBlock* cxx_exc_dest; - UnwindInfo(AST_stmt* current_stmt, llvm::BasicBlock* exc_dest) : current_stmt(current_stmt), exc_dest(exc_dest) {} + bool hasHandler() const { return cxx_exc_dest != NULL || capi_exc_dest != NULL; } + + UnwindInfo(AST_stmt* current_stmt, llvm::BasicBlock* capi_exc_dest, llvm::BasicBlock* cxx_exc_dest) + : current_stmt(current_stmt), capi_exc_dest(capi_exc_dest), cxx_exc_dest(cxx_exc_dest) {} // 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); } + static UnwindInfo cantUnwind() { return UnwindInfo(NULL, NULL, NULL); } }; // TODO get rid of this @@ -78,16 +81,23 @@ class IREmitter { virtual llvm::Function* getIntrinsic(llvm::Intrinsic::ID) = 0; - virtual llvm::Value* createCall(UnwindInfo unw_info, llvm::Value* callee, const std::vector& args) + virtual llvm::Value* createCall(const UnwindInfo& unw_info, llvm::Value* callee, + const std::vector& args, ExceptionStyle target_exception_style = CXX) = 0; - virtual llvm::Value* createCall(UnwindInfo unw_info, llvm::Value* callee) = 0; - virtual llvm::Value* createCall(UnwindInfo unw_info, llvm::Value* callee, llvm::Value* arg1) = 0; - virtual llvm::Value* createCall2(UnwindInfo unw_info, llvm::Value* callee, llvm::Value* arg1, llvm::Value* arg2) + virtual llvm::Value* createCall(const UnwindInfo& unw_info, llvm::Value* callee, + ExceptionStyle target_exception_style = CXX) = 0; + virtual llvm::Value* createCall(const UnwindInfo& unw_info, llvm::Value* callee, llvm::Value* arg1, + ExceptionStyle target_exception_style = CXX) = 0; + virtual llvm::Value* createCall2(const UnwindInfo& unw_info, llvm::Value* callee, llvm::Value* arg1, + llvm::Value* arg2, ExceptionStyle target_exception_style = CXX) = 0; + virtual llvm::Value* createCall3(const UnwindInfo& unw_info, llvm::Value* callee, llvm::Value* arg1, + llvm::Value* arg2, llvm::Value* arg3, ExceptionStyle target_exception_style = CXX) = 0; - virtual llvm::Value* createCall3(UnwindInfo unw_info, llvm::Value* callee, llvm::Value* arg1, llvm::Value* arg2, - llvm::Value* arg3) = 0; virtual llvm::Value* createIC(const ICSetupInfo* pp, void* func_addr, const std::vector& args, - UnwindInfo unw_info) = 0; + const UnwindInfo& unw_info, ExceptionStyle target_exception_style = CXX) = 0; + + virtual void checkAndPropagateCapiException(const UnwindInfo& unw_info, llvm::Value* returned_val, + llvm::Value* exc_val, bool double_check = false) = 0; virtual Box* getIntConstant(int64_t n) = 0; virtual Box* getFloatConstant(double d) = 0; @@ -132,7 +142,7 @@ class OpInfo { public: const UnwindInfo unw_info; - OpInfo(EffortLevel effort, TypeRecorder* type_recorder, UnwindInfo unw_info) + OpInfo(EffortLevel effort, TypeRecorder* type_recorder, const UnwindInfo& unw_info) : effort(effort), type_recorder(type_recorder), unw_info(unw_info) {} TypeRecorder* getTypeRecorder() const { return type_recorder; } diff --git a/src/codegen/irgen/hooks.cpp b/src/codegen/irgen/hooks.cpp index 2b5145f8e..74c6288cc 100644 --- a/src/codegen/irgen/hooks.cpp +++ b/src/codegen/irgen/hooks.cpp @@ -716,8 +716,7 @@ void CompiledFunction::speculationFailed() { } CompiledFunction::CompiledFunction(llvm::Function* func, FunctionSpecialization* spec, void* code, EffortLevel effort, - ExceptionStyle::ExceptionStyle exception_style, - const OSREntryDescriptor* entry_descriptor) + ExceptionStyle exception_style, const OSREntryDescriptor* entry_descriptor) : clfunc(NULL), func(func), spec(spec), @@ -834,7 +833,7 @@ CLFunction* createRTFunction(int num_args, int num_defaults, bool takes_varargs, } CLFunction* boxRTFunction(void* f, ConcreteCompilerType* rtn_type, int num_args, const ParamNames& param_names, - ExceptionStyle::ExceptionStyle exception_style) { + ExceptionStyle exception_style) { assert(!param_names.takes_param_names || num_args == param_names.args.size()); assert(param_names.vararg.str() == ""); assert(param_names.kwarg.str() == ""); @@ -843,8 +842,7 @@ CLFunction* boxRTFunction(void* f, ConcreteCompilerType* rtn_type, int num_args, } CLFunction* boxRTFunction(void* f, ConcreteCompilerType* rtn_type, int num_args, int num_defaults, bool takes_varargs, - bool takes_kwargs, const ParamNames& param_names, - ExceptionStyle::ExceptionStyle exception_style) { + bool takes_kwargs, const ParamNames& param_names, ExceptionStyle exception_style) { assert(!param_names.takes_param_names || num_args == param_names.args.size()); assert(takes_varargs || param_names.vararg.str() == ""); assert(takes_kwargs || param_names.kwarg.str() == ""); @@ -855,8 +853,7 @@ CLFunction* boxRTFunction(void* f, ConcreteCompilerType* rtn_type, int num_args, return cl_f; } -void addRTFunction(CLFunction* cl_f, void* f, ConcreteCompilerType* rtn_type, - ExceptionStyle::ExceptionStyle exception_style) { +void addRTFunction(CLFunction* cl_f, void* f, ConcreteCompilerType* rtn_type, ExceptionStyle exception_style) { std::vector arg_types(cl_f->numReceivedArgs(), UNKNOWN); return addRTFunction(cl_f, f, rtn_type, arg_types, exception_style); } @@ -867,8 +864,7 @@ static ConcreteCompilerType* processType(ConcreteCompilerType* type) { } void addRTFunction(CLFunction* cl_f, void* f, ConcreteCompilerType* rtn_type, - const std::vector& arg_types, - ExceptionStyle::ExceptionStyle exception_style) { + const std::vector& arg_types, ExceptionStyle exception_style) { assert(arg_types.size() == cl_f->numReceivedArgs()); #ifndef NDEBUG for (ConcreteCompilerType* t : arg_types) diff --git a/src/codegen/irgen/hooks.h b/src/codegen/irgen/hooks.h index b983a3c55..f05c49084 100644 --- a/src/codegen/irgen/hooks.h +++ b/src/codegen/irgen/hooks.h @@ -39,6 +39,8 @@ void compileAndRunModule(AST_Module* m, BoxedModule* bm); // will we always want to generate unique function names? (ie will this function always be reasonable?) CompiledFunction* cfForMachineFunctionName(const std::string&); +extern "C" void capiExcCaughtInJit(AST_stmt* current_stmt, void* source_info); + extern "C" Box* exec(Box* boxedCode, Box* globals, Box* locals, FutureFlags caller_future_flags); extern "C" Box* eval(Box* boxedCode, Box* globals, Box* locals); extern "C" Box* compile(Box* source, Box* filename, Box* mode, Box** _args /* flags, dont_inherit */); diff --git a/src/codegen/irgen/irgenerator.cpp b/src/codegen/irgen/irgenerator.cpp index 1cce363b9..2c5a1fd37 100644 --- a/src/codegen/irgen/irgenerator.cpp +++ b/src/codegen/irgen/irgenerator.cpp @@ -37,7 +37,8 @@ namespace pyston { -extern "C" void dumpLLVM(llvm::Value* v) { +extern "C" void dumpLLVM(void* _v) { + llvm::Value* v = (llvm::Value*)_v; v->getType()->dump(); v->dump(); } @@ -93,6 +94,55 @@ llvm::Value* IRGenState::getScratchSpace(int min_bytes) { return scratch_space; } +// This function is where we decide whether to have a certain operation use CAPI or CXX exceptions. +// FIXME It's a bit messy at the moment because this requires coordinating between a couple different +// parts: we need to make sure that the associated landingpad will catch the right kind of exception, +// and we need to make sure that we can actually emit this statement using capi-exceptions. +// It doesn't really belong on the IRGenState, but it's here so that we can access this state from +// separate basic blocks (the IRGenerator only exists for a single bb). +ExceptionStyle IRGenState::getLandingpadStyle(AST_Invoke* invoke) { + assert(!landingpad_styles.count(invoke->exc_dest)); + ExceptionStyle& r = landingpad_styles[invoke->exc_dest]; + // printf("Added %d\n", invoke->exc_dest->idx); + + r = CXX; // default + + // print_ast(invoke); + // printf("\n"); + AST_expr* expr = NULL; + + if (invoke->stmt->type == AST_TYPE::Assign) { + expr = ast_cast(invoke->stmt)->value; + } else if (invoke->stmt->type == AST_TYPE::Expr) { + expr = ast_cast(invoke->stmt)->value; + } + + if (!expr) + return r; + + if (0 && expr->type == AST_TYPE::Call) { + AST_Call* call = ast_cast(expr); + if (call->func->type != AST_TYPE::Attribute && call->func->type != AST_TYPE::ClsAttribute) { + r = CAPI; + // printf("Doing a capi exception to %d\n", invoke->exc_dest->idx); + } + return r; + } + + if (expr->type == AST_TYPE::Attribute) { + r = CAPI; + // printf("Doing a capi exception to %d\n", invoke->exc_dest->idx); + return r; + } + + return r; +} + +ExceptionStyle IRGenState::getLandingpadStyle(CFGBlock* block) { + ASSERT(landingpad_styles.count(block), "%d", block->idx); + return landingpad_styles[block]; +} + static llvm::Value* getClosureParentGep(IREmitter& emitter, llvm::Value* closure) { static_assert(sizeof(Box) == offsetof(BoxedClosure, parent), ""); static_assert(offsetof(BoxedClosure, parent) + sizeof(BoxedClosure*) == offsetof(BoxedClosure, nelts), ""); @@ -230,25 +280,64 @@ class IREmitterImpl : public IREmitter { llvm::BasicBlock*& curblock; IRGenerator* irgenerator; - llvm::CallSite emitCall(UnwindInfo unw_info, llvm::Value* callee, const std::vector& args) { - if (unw_info.needsInvoke()) { + llvm::CallSite emitCall(const UnwindInfo& unw_info, llvm::Value* callee, const std::vector& args, + ExceptionStyle target_exception_style) { + if (unw_info.hasHandler() && target_exception_style == CXX) { + assert(unw_info.cxx_exc_dest); llvm::BasicBlock* normal_dest = llvm::BasicBlock::Create(g.context, curblock->getName(), irstate->getLLVMFunction()); normal_dest->moveAfter(curblock); - llvm::InvokeInst* rtn = getBuilder()->CreateInvoke(callee, normal_dest, unw_info.exc_dest, args); + llvm::InvokeInst* rtn = getBuilder()->CreateInvoke(callee, normal_dest, unw_info.cxx_exc_dest, args); getBuilder()->SetInsertPoint(normal_dest); curblock = normal_dest; return rtn; } else { - return getBuilder()->CreateCall(callee, args); + llvm::CallInst* cs = getBuilder()->CreateCall(callee, args); + return cs; } } + void checkAndPropagateCapiException(const UnwindInfo& unw_info, llvm::Value* returned_val, llvm::Value* exc_val, + bool double_check) { + assert(!double_check); // need to call PyErr_Occurred + + llvm::BasicBlock* normal_dest + = llvm::BasicBlock::Create(g.context, curblock->getName(), irstate->getLLVMFunction()); + normal_dest->moveAfter(curblock); + + llvm::BasicBlock* exc_dest; + bool exc_caught; + if (unw_info.hasHandler()) { + assert(unw_info.capi_exc_dest); + exc_dest = unw_info.capi_exc_dest; + exc_caught = true; + } else { + exc_dest = llvm::BasicBlock::Create(g.context, curblock->getName() + "_exc", irstate->getLLVMFunction()); + exc_dest->moveAfter(curblock); + exc_caught = false; + } + + assert(returned_val->getType() == exc_val->getType()); + llvm::Value* check_val = getBuilder()->CreateICmpEQ(returned_val, exc_val); + llvm::BranchInst* nullcheck = getBuilder()->CreateCondBr(check_val, exc_dest, normal_dest); + + setCurrentBasicBlock(exc_dest); + getBuilder()->CreateCall2(g.funcs.capiExcCaughtInJit, + embedRelocatablePtr(unw_info.current_stmt, g.llvm_aststmt_type_ptr), + embedRelocatablePtr(irstate->getSourceInfo(), g.i8_ptr)); + + if (!exc_caught) { + RELEASE_ASSERT(0, "need to implement this"); + } + + setCurrentBasicBlock(normal_dest); + } llvm::CallSite emitPatchpoint(llvm::Type* return_type, const ICSetupInfo* pp, llvm::Value* func, const std::vector& args, - const std::vector& ic_stackmap_args, UnwindInfo unw_info) { + const std::vector& ic_stackmap_args, const UnwindInfo& unw_info, + ExceptionStyle target_exception_style) { if (pp == NULL) assert(ic_stackmap_args.size() == 0); @@ -272,7 +361,7 @@ class IREmitterImpl : public IREmitter { int pp_size = pp ? pp->totalSize() : CALL_ONLY_SIZE; std::vector pp_args; - pp_args.push_back(getConstantInt(pp_id, g.i64)); // pp_id: will fill this in later + pp_args.push_back(getConstantInt(pp_id, g.i64)); pp_args.push_back(getConstantInt(pp_size, g.i32)); if (ENABLE_JIT_OBJECT_CACHE) // add fixed dummy dest pointer, we will replace it with the correct address during stackmap processing @@ -304,7 +393,7 @@ class IREmitterImpl : public IREmitter { } llvm::Function* patchpoint = this->getIntrinsic(intrinsic_id); - llvm::CallSite rtn = this->emitCall(unw_info, patchpoint, pp_args); + llvm::CallSite rtn = this->emitCall(unw_info, patchpoint, pp_args, target_exception_style); return rtn; } @@ -343,7 +432,8 @@ class IREmitterImpl : public IREmitter { return llvm::BasicBlock::Create(g.context, name, irstate->getLLVMFunction()); } - llvm::Value* createCall(UnwindInfo unw_info, llvm::Value* callee, const std::vector& args) override { + llvm::Value* createCall(const UnwindInfo& unw_info, llvm::Value* callee, const std::vector& args, + ExceptionStyle target_exception_style = CXX) override { #ifndef NDEBUG // Copied the argument-type-checking from CallInst::init, since the patchpoint arguments don't // get checked. @@ -367,7 +457,7 @@ class IREmitterImpl : public IREmitter { ->getElementType())->getReturnType(); llvm::Value* bitcasted = getBuilder()->CreateBitCast(callee, g.i8->getPointerTo()); - llvm::CallSite cs = emitPatchpoint(rtn_type, NULL, bitcasted, args, {}, unw_info); + llvm::CallSite cs = emitPatchpoint(rtn_type, NULL, bitcasted, args, {}, unw_info, target_exception_style); if (rtn_type == cs->getType()) { return cs.getInstruction(); @@ -381,34 +471,37 @@ class IREmitterImpl : public IREmitter { RELEASE_ASSERT(0, "don't know how to convert those"); } } else { - return emitCall(unw_info, callee, args).getInstruction(); + return emitCall(unw_info, callee, args, target_exception_style).getInstruction(); } } - llvm::Value* createCall(UnwindInfo unw_info, llvm::Value* callee) override { - return createCall(unw_info, callee, std::vector()); + llvm::Value* createCall(const UnwindInfo& unw_info, llvm::Value* callee, + ExceptionStyle target_exception_style = CXX) override { + return createCall(unw_info, callee, std::vector(), target_exception_style); } - llvm::Value* createCall(UnwindInfo unw_info, llvm::Value* callee, llvm::Value* arg1) override { - return createCall(unw_info, callee, std::vector({ arg1 })); + llvm::Value* createCall(const UnwindInfo& unw_info, llvm::Value* callee, llvm::Value* arg1, + ExceptionStyle target_exception_style = CXX) override { + return createCall(unw_info, callee, std::vector({ arg1 }), target_exception_style); } - llvm::Value* createCall2(UnwindInfo unw_info, llvm::Value* callee, llvm::Value* arg1, llvm::Value* arg2) override { - return createCall(unw_info, callee, { arg1, arg2 }); + llvm::Value* createCall2(const UnwindInfo& unw_info, llvm::Value* callee, llvm::Value* arg1, llvm::Value* arg2, + ExceptionStyle target_exception_style = CXX) override { + return createCall(unw_info, callee, { arg1, arg2 }, target_exception_style); } - llvm::Value* createCall3(UnwindInfo unw_info, llvm::Value* callee, llvm::Value* arg1, llvm::Value* arg2, - llvm::Value* arg3) override { - return createCall(unw_info, callee, { arg1, arg2, arg3 }); + llvm::Value* createCall3(const UnwindInfo& unw_info, llvm::Value* callee, llvm::Value* arg1, llvm::Value* arg2, + llvm::Value* arg3, ExceptionStyle target_exception_style = CXX) override { + return createCall(unw_info, callee, { arg1, arg2, arg3 }, target_exception_style); } llvm::Value* createIC(const ICSetupInfo* pp, void* func_addr, const std::vector& args, - UnwindInfo unw_info) override { + const UnwindInfo& unw_info, ExceptionStyle target_exception_style = CXX) override { std::vector stackmap_args; - llvm::CallSite rtn - = emitPatchpoint(pp->hasReturnValue() ? g.i64 : g.void_, pp, - embedConstantPtr(func_addr, g.i8->getPointerTo()), args, stackmap_args, unw_info); + llvm::CallSite rtn = emitPatchpoint(pp->hasReturnValue() ? g.i64 : g.void_, pp, + embedConstantPtr(func_addr, g.i8->getPointerTo()), args, stackmap_args, + unw_info, target_exception_style); rtn.setCallingConv(pp->getCallingConvention()); return rtn.getInstruction(); @@ -489,7 +582,7 @@ class IRGeneratorImpl : public IRGenerator { ~IRGeneratorImpl() { delete emitter.getBuilder(); } private: - OpInfo getOpInfoForNode(AST* ast, UnwindInfo unw_info) { + OpInfo getOpInfoForNode(AST* ast, const UnwindInfo& unw_info) { assert(ast); EffortLevel effort = irstate->getEffortLevel(); @@ -508,7 +601,7 @@ class IRGeneratorImpl : public IRGenerator { return OpInfo(irstate->getEffortLevel(), type_recorder, unw_info); } - OpInfo getEmptyOpInfo(UnwindInfo unw_info) { return OpInfo(irstate->getEffortLevel(), NULL, unw_info); } + OpInfo getEmptyOpInfo(const UnwindInfo& unw_info) { return OpInfo(irstate->getEffortLevel(), NULL, unw_info); } void createExprTypeGuard(llvm::Value* check_val, AST_expr* node, llvm::Value* node_value, AST_stmt* current_statement) { @@ -532,7 +625,7 @@ class IRGeneratorImpl : public IRGenerator { curblock = deopt_bb; emitter.getBuilder()->SetInsertPoint(curblock); - llvm::Value* v = emitter.createCall2(UnwindInfo(current_statement, NULL), g.funcs.deopt, + llvm::Value* v = emitter.createCall2(UnwindInfo(current_statement, NULL, NULL), g.funcs.deopt, embedRelocatablePtr(node, g.llvm_aststmt_type_ptr), node_value); emitter.getBuilder()->CreateRet(v); @@ -548,7 +641,7 @@ class IRGeneratorImpl : public IRGenerator { return pyston::getIsDefinedName(name, irstate->getSourceInfo()->getInternedStrings()); } - CompilerVariable* evalAttribute(AST_Attribute* node, UnwindInfo unw_info) { + CompilerVariable* evalAttribute(AST_Attribute* node, const UnwindInfo& unw_info) { CompilerVariable* value = evalExpr(node->value, unw_info); CompilerVariable* rtn = value->getattr(emitter, getOpInfoForNode(node, unw_info), node->attr.getBox(), false); @@ -556,14 +649,14 @@ class IRGeneratorImpl : public IRGenerator { return rtn; } - CompilerVariable* evalClsAttribute(AST_ClsAttribute* node, UnwindInfo unw_info) { + CompilerVariable* evalClsAttribute(AST_ClsAttribute* node, const UnwindInfo& unw_info) { CompilerVariable* value = evalExpr(node->value, unw_info); CompilerVariable* rtn = value->getattr(emitter, getOpInfoForNode(node, unw_info), node->attr.getBox(), true); value->decvref(emitter); return rtn; } - CompilerVariable* evalLangPrimitive(AST_LangPrimitive* node, UnwindInfo unw_info) { + CompilerVariable* evalLangPrimitive(AST_LangPrimitive* node, const UnwindInfo& unw_info) { switch (node->opcode) { case AST_LangPrimitive::CHECK_EXC_MATCH: { assert(node->args.size() == 2); @@ -582,38 +675,59 @@ class IRGeneratorImpl : public IRGenerator { return boolFromI1(emitter, v); } case AST_LangPrimitive::LANDINGPAD: { - // llvm::Function* _personality_func = g.stdlib_module->getFunction("__py_personality_v0"); - llvm::Function* _personality_func = g.stdlib_module->getFunction("__gxx_personality_v0"); - assert(_personality_func); - llvm::Value* personality_func = g.cur_module->getOrInsertFunction(_personality_func->getName(), - _personality_func->getFunctionType()); - assert(personality_func); - llvm::LandingPadInst* landing_pad = emitter.getBuilder()->CreateLandingPad( - llvm::StructType::create(std::vector{ g.i8_ptr, g.i64 }), personality_func, 1); - landing_pad->addClause(getNullPtr(g.i8_ptr)); - - llvm::Value* cxaexc_pointer = emitter.getBuilder()->CreateExtractValue(landing_pad, { 0 }); - - llvm::Function* std_module_catch = g.stdlib_module->getFunction("__cxa_begin_catch"); - auto begin_catch_func = g.cur_module->getOrInsertFunction(std_module_catch->getName(), - std_module_catch->getFunctionType()); - assert(begin_catch_func); - - llvm::Value* excinfo_pointer = emitter.getBuilder()->CreateCall(begin_catch_func, cxaexc_pointer); - llvm::Value* excinfo_pointer_casted - = emitter.getBuilder()->CreateBitCast(excinfo_pointer, g.llvm_excinfo_type->getPointerTo()); + llvm::Value* exc_type; + llvm::Value* exc_value; + llvm::Value* exc_traceback; + if (irstate->getLandingpadStyle(myblock) == CXX) { + // llvm::Function* _personality_func = g.stdlib_module->getFunction("__py_personality_v0"); + llvm::Function* _personality_func = g.stdlib_module->getFunction("__gxx_personality_v0"); + assert(_personality_func); + llvm::Value* personality_func = g.cur_module->getOrInsertFunction( + _personality_func->getName(), _personality_func->getFunctionType()); + assert(personality_func); + llvm::LandingPadInst* landing_pad = emitter.getBuilder()->CreateLandingPad( + llvm::StructType::create(std::vector{ g.i8_ptr, g.i64 }), personality_func, 1); + landing_pad->addClause(getNullPtr(g.i8_ptr)); + + llvm::Value* cxaexc_pointer = emitter.getBuilder()->CreateExtractValue(landing_pad, { 0 }); + + llvm::Function* std_module_catch = g.stdlib_module->getFunction("__cxa_begin_catch"); + auto begin_catch_func = g.cur_module->getOrInsertFunction(std_module_catch->getName(), + std_module_catch->getFunctionType()); + assert(begin_catch_func); + + llvm::Value* excinfo_pointer = emitter.getBuilder()->CreateCall(begin_catch_func, cxaexc_pointer); + llvm::Value* excinfo_pointer_casted + = emitter.getBuilder()->CreateBitCast(excinfo_pointer, g.llvm_excinfo_type->getPointerTo()); + + auto* builder = emitter.getBuilder(); + exc_type = builder->CreateLoad(builder->CreateConstInBoundsGEP2_32(excinfo_pointer_casted, 0, 0)); + exc_value = builder->CreateLoad(builder->CreateConstInBoundsGEP2_32(excinfo_pointer_casted, 0, 1)); + exc_traceback + = builder->CreateLoad(builder->CreateConstInBoundsGEP2_32(excinfo_pointer_casted, 0, 2)); + } else { + llvm::Value* exc_type_ptr + = new llvm::AllocaInst(g.llvm_value_type_ptr, getConstantInt(1, g.i64), "exc_type", + irstate->getLLVMFunction()->getEntryBlock().getFirstInsertionPt()); + llvm::Value* exc_value_ptr + = new llvm::AllocaInst(g.llvm_value_type_ptr, getConstantInt(1, g.i64), "exc_value", + irstate->getLLVMFunction()->getEntryBlock().getFirstInsertionPt()); + llvm::Value* exc_traceback_ptr + = new llvm::AllocaInst(g.llvm_value_type_ptr, getConstantInt(1, g.i64), "exc_traceback", + irstate->getLLVMFunction()->getEntryBlock().getFirstInsertionPt()); + emitter.getBuilder()->CreateCall3(g.funcs.PyErr_Fetch, exc_type_ptr, exc_value_ptr, + exc_traceback_ptr); + // TODO: I think we should be doing this on a python raise() or when we enter a python catch: + emitter.getBuilder()->CreateCall3(g.funcs.PyErr_NormalizeException, exc_type_ptr, exc_value_ptr, + exc_traceback_ptr); + exc_type = emitter.getBuilder()->CreateLoad(exc_type_ptr); + exc_value = emitter.getBuilder()->CreateLoad(exc_value_ptr); + exc_traceback = emitter.getBuilder()->CreateLoad(exc_traceback_ptr); + } - auto* builder = emitter.getBuilder(); - llvm::Value* exc_type - = builder->CreateLoad(builder->CreateConstInBoundsGEP2_32(excinfo_pointer_casted, 0, 0)); - llvm::Value* exc_value - = builder->CreateLoad(builder->CreateConstInBoundsGEP2_32(excinfo_pointer_casted, 0, 1)); - llvm::Value* exc_traceback - = builder->CreateLoad(builder->CreateConstInBoundsGEP2_32(excinfo_pointer_casted, 0, 2)); assert(exc_type->getType() == g.llvm_value_type_ptr); assert(exc_value->getType() == g.llvm_value_type_ptr); assert(exc_traceback->getType() == g.llvm_value_type_ptr); - return makeTuple({ new ConcreteCompilerVariable(UNKNOWN, exc_type, true), new ConcreteCompilerVariable(UNKNOWN, exc_value, true), new ConcreteCompilerVariable(UNKNOWN, exc_traceback, true) }); @@ -763,7 +877,7 @@ class IRGeneratorImpl : public IRGenerator { } CompilerVariable* _evalBinExp(AST* node, CompilerVariable* left, CompilerVariable* right, AST_TYPE::AST_TYPE type, - BinExpType exp_type, UnwindInfo unw_info) { + BinExpType exp_type, const UnwindInfo& unw_info) { assert(left); assert(right); @@ -783,7 +897,7 @@ class IRGeneratorImpl : public IRGenerator { return left->binexp(emitter, getOpInfoForNode(node, unw_info), right, type, exp_type); } - CompilerVariable* evalBinOp(AST_BinOp* node, UnwindInfo unw_info) { + CompilerVariable* evalBinOp(AST_BinOp* node, const UnwindInfo& unw_info) { CompilerVariable* left = evalExpr(node->left, unw_info); CompilerVariable* right = evalExpr(node->right, unw_info); @@ -795,7 +909,7 @@ class IRGeneratorImpl : public IRGenerator { return rtn; } - CompilerVariable* evalAugBinOp(AST_AugBinOp* node, UnwindInfo unw_info) { + CompilerVariable* evalAugBinOp(AST_AugBinOp* node, const UnwindInfo& unw_info) { CompilerVariable* left = evalExpr(node->left, unw_info); CompilerVariable* right = evalExpr(node->right, unw_info); @@ -807,7 +921,7 @@ class IRGeneratorImpl : public IRGenerator { return rtn; } - CompilerVariable* evalCompare(AST_Compare* node, UnwindInfo unw_info) { + CompilerVariable* evalCompare(AST_Compare* node, const UnwindInfo& unw_info) { RELEASE_ASSERT(node->ops.size() == 1, ""); CompilerVariable* left = evalExpr(node->left, unw_info); @@ -826,7 +940,7 @@ class IRGeneratorImpl : public IRGenerator { return rtn; } - CompilerVariable* evalCall(AST_Call* node, UnwindInfo unw_info) { + CompilerVariable* evalCall(AST_Call* node, const UnwindInfo& unw_info) { bool is_callattr; bool callattr_clsonly = false; InternedString attr; @@ -891,7 +1005,7 @@ class IRGeneratorImpl : public IRGenerator { return rtn; } - CompilerVariable* evalDict(AST_Dict* node, UnwindInfo unw_info) { + CompilerVariable* evalDict(AST_Dict* node, const UnwindInfo& unw_info) { llvm::Value* v = emitter.getBuilder()->CreateCall(g.funcs.createDict); ConcreteCompilerVariable* rtn = new ConcreteCompilerVariable(DICT, v, true); if (node->keys.size()) { @@ -926,9 +1040,9 @@ class IRGeneratorImpl : public IRGenerator { inst->setMetadata(message, mdnode); } - CompilerVariable* evalIndex(AST_Index* node, UnwindInfo unw_info) { return evalExpr(node->value, unw_info); } + CompilerVariable* evalIndex(AST_Index* node, const UnwindInfo& unw_info) { return evalExpr(node->value, unw_info); } - CompilerVariable* evalLambda(AST_Lambda* node, UnwindInfo unw_info) { + CompilerVariable* evalLambda(AST_Lambda* node, const UnwindInfo& unw_info) { AST_Return* expr = new AST_Return(); expr->value = node->body; @@ -941,7 +1055,7 @@ class IRGeneratorImpl : public IRGenerator { } - CompilerVariable* evalList(AST_List* node, UnwindInfo unw_info) { + CompilerVariable* evalList(AST_List* node, const UnwindInfo& unw_info) { std::vector elts; for (int i = 0; i < node->elts.size(); i++) { CompilerVariable* value = evalExpr(node->elts[i], unw_info); @@ -977,7 +1091,7 @@ class IRGeneratorImpl : public IRGenerator { return embedRelocatablePtr(parent_module, g.llvm_value_type_ptr, "cParentModule"); } - ConcreteCompilerVariable* _getGlobal(AST_Name* node, UnwindInfo unw_info) { + ConcreteCompilerVariable* _getGlobal(AST_Name* node, const UnwindInfo& unw_info) { if (node->id.s() == "None") return getNone(); @@ -999,7 +1113,7 @@ class IRGeneratorImpl : public IRGenerator { } } - CompilerVariable* evalName(AST_Name* node, UnwindInfo unw_info) { + CompilerVariable* evalName(AST_Name* node, const UnwindInfo& unw_info) { auto scope_info = irstate->getScopeInfo(); bool is_kill = irstate->getLiveness()->isKill(node, myblock); @@ -1100,7 +1214,7 @@ class IRGeneratorImpl : public IRGenerator { } } - CompilerVariable* evalNum(AST_Num* node, UnwindInfo unw_info) { + CompilerVariable* evalNum(AST_Num* node, const UnwindInfo& unw_info) { // We can operate on ints and floats unboxed, so don't box those at first; // complex and long's have to get boxed so box them immediately. if (node->num_type == AST_Num::INT) { @@ -1114,7 +1228,7 @@ class IRGeneratorImpl : public IRGenerator { } } - CompilerVariable* evalRepr(AST_Repr* node, UnwindInfo unw_info) { + CompilerVariable* evalRepr(AST_Repr* node, const UnwindInfo& unw_info) { CompilerVariable* var = evalExpr(node->value, unw_info); ConcreteCompilerVariable* cvar = var->makeConverted(emitter, var->getBoxType()); var->decvref(emitter); @@ -1127,7 +1241,7 @@ class IRGeneratorImpl : public IRGenerator { return new ConcreteCompilerVariable(STR, rtn, true); } - CompilerVariable* evalSet(AST_Set* node, UnwindInfo unw_info) { + CompilerVariable* evalSet(AST_Set* node, const UnwindInfo& unw_info) { std::vector elts; for (int i = 0; i < node->elts.size(); i++) { CompilerVariable* value = evalExpr(node->elts[i], unw_info); @@ -1151,7 +1265,7 @@ class IRGeneratorImpl : public IRGenerator { return rtn; } - CompilerVariable* evalSlice(AST_Slice* node, UnwindInfo unw_info) { + CompilerVariable* evalSlice(AST_Slice* node, const UnwindInfo& unw_info) { CompilerVariable* start, *stop, *step; start = node->lower ? evalExpr(node->lower, unw_info) : getNone(); stop = node->upper ? evalExpr(node->upper, unw_info) : getNone(); @@ -1177,7 +1291,7 @@ class IRGeneratorImpl : public IRGenerator { return new ConcreteCompilerVariable(SLICE, rtn, true); } - CompilerVariable* evalExtSlice(AST_ExtSlice* node, UnwindInfo unw_info) { + CompilerVariable* evalExtSlice(AST_ExtSlice* node, const UnwindInfo& unw_info) { std::vector elts; for (auto* e : node->dims) { elts.push_back(evalExpr(e, unw_info)); @@ -1191,7 +1305,7 @@ class IRGeneratorImpl : public IRGenerator { return rtn; } - CompilerVariable* evalStr(AST_Str* node, UnwindInfo unw_info) { + CompilerVariable* evalStr(AST_Str* node, const UnwindInfo& unw_info) { if (node->str_type == AST_Str::STR) { llvm::Value* rtn = embedRelocatablePtr( irstate->getSourceInfo()->parent_module->getStringConstant(node->str_data), g.llvm_value_type_ptr); @@ -1207,7 +1321,7 @@ class IRGeneratorImpl : public IRGenerator { } } - CompilerVariable* evalSubscript(AST_Subscript* node, UnwindInfo unw_info) { + CompilerVariable* evalSubscript(AST_Subscript* node, const UnwindInfo& unw_info) { CompilerVariable* value = evalExpr(node->value, unw_info); CompilerVariable* slice = evalExpr(node->slice, unw_info); @@ -1217,7 +1331,7 @@ class IRGeneratorImpl : public IRGenerator { return rtn; } - CompilerVariable* evalTuple(AST_Tuple* node, UnwindInfo unw_info) { + CompilerVariable* evalTuple(AST_Tuple* node, const UnwindInfo& unw_info) { std::vector elts; for (int i = 0; i < node->elts.size(); i++) { CompilerVariable* value = evalExpr(node->elts[i], unw_info); @@ -1232,7 +1346,7 @@ class IRGeneratorImpl : public IRGenerator { return rtn; } - CompilerVariable* evalUnaryOp(AST_UnaryOp* node, UnwindInfo unw_info) { + CompilerVariable* evalUnaryOp(AST_UnaryOp* node, const UnwindInfo& unw_info) { CompilerVariable* operand = evalExpr(node->operand, unw_info); if (node->op_type == AST_TYPE::Not) { @@ -1259,7 +1373,7 @@ class IRGeneratorImpl : public IRGenerator { } } - CompilerVariable* evalYield(AST_Yield* node, UnwindInfo unw_info) { + CompilerVariable* evalYield(AST_Yield* node, const UnwindInfo& unw_info) { CompilerVariable* generator = symbol_table[internString(PASSED_GENERATOR_NAME)]; assert(generator); ConcreteCompilerVariable* convertedGenerator = generator->makeConverted(emitter, generator->getBoxType()); @@ -1277,7 +1391,7 @@ class IRGeneratorImpl : public IRGenerator { return new ConcreteCompilerVariable(UNKNOWN, rtn, true); } - CompilerVariable* evalMakeClass(AST_MakeClass* mkclass, UnwindInfo unw_info) { + CompilerVariable* evalMakeClass(AST_MakeClass* mkclass, const UnwindInfo& unw_info) { assert(mkclass->type == AST_TYPE::MakeClass && mkclass->class_def->type == AST_TYPE::ClassDef); AST_ClassDef* node = mkclass->class_def; ScopeInfo* scope_info = irstate->getScopeInfoForNode(node); @@ -1346,7 +1460,7 @@ class IRGeneratorImpl : public IRGenerator { return cls; } - CompilerVariable* _createFunction(AST* node, UnwindInfo unw_info, AST_arguments* args, + CompilerVariable* _createFunction(AST* node, const UnwindInfo& unw_info, AST_arguments* args, const std::vector& body) { CLFunction* cl = wrapFunction(node, args, body, irstate->getSourceInfo()); @@ -1394,7 +1508,7 @@ class IRGeneratorImpl : public IRGenerator { return func; } - CompilerVariable* evalMakeFunction(AST_MakeFunction* mkfn, UnwindInfo unw_info) { + CompilerVariable* evalMakeFunction(AST_MakeFunction* mkfn, const UnwindInfo& unw_info) { AST_FunctionDef* node = mkfn->function_def; std::vector decorators; for (auto d : node->decorator_list) { @@ -1429,7 +1543,7 @@ class IRGeneratorImpl : public IRGenerator { return new ConcreteCompilerVariable(t, v, grabbed); } - CompilerVariable* evalExpr(AST_expr* node, UnwindInfo unw_info) { + CompilerVariable* evalExpr(AST_expr* node, const UnwindInfo& unw_info) { // printf("%d expr: %d\n", node->type, node->lineno); if (node->lineno) { emitter.getBuilder()->SetCurrentDebugLocation( @@ -1584,7 +1698,7 @@ class IRGeneratorImpl : public IRGenerator { } // only updates symbol_table if we're *not* setting a global - void _doSet(InternedString name, CompilerVariable* val, UnwindInfo unw_info) { + void _doSet(InternedString name, CompilerVariable* val, const UnwindInfo& unw_info) { assert(name.s() != "None"); assert(name.s() != FRAME_INFO_PTR_NAME); @@ -1632,13 +1746,13 @@ class IRGeneratorImpl : public IRGenerator { } } - void _doSetattr(AST_Attribute* target, CompilerVariable* val, UnwindInfo unw_info) { + void _doSetattr(AST_Attribute* target, CompilerVariable* val, const UnwindInfo& unw_info) { CompilerVariable* t = evalExpr(target->value, unw_info); t->setattr(emitter, getEmptyOpInfo(unw_info), target->attr.getBox(), val); t->decvref(emitter); } - void _doSetitem(AST_Subscript* target, CompilerVariable* val, UnwindInfo unw_info) { + void _doSetitem(AST_Subscript* target, CompilerVariable* val, const UnwindInfo& unw_info) { CompilerVariable* tget = evalExpr(target->value, unw_info); CompilerVariable* slice = evalExpr(target->slice, unw_info); @@ -1672,7 +1786,7 @@ class IRGeneratorImpl : public IRGenerator { converted_val->decvref(emitter); } - void _doUnpackTuple(AST_Tuple* target, CompilerVariable* val, UnwindInfo unw_info) { + void _doUnpackTuple(AST_Tuple* target, CompilerVariable* val, const UnwindInfo& unw_info) { int ntargets = target->elts.size(); std::vector unpacked = val->unpack(emitter, getOpInfoForNode(target, unw_info), ntargets); @@ -1691,7 +1805,7 @@ class IRGeneratorImpl : public IRGenerator { } } - void _doSet(AST* target, CompilerVariable* val, UnwindInfo unw_info) { + void _doSet(AST* target, CompilerVariable* val, const UnwindInfo& unw_info) { switch (target->type) { case AST_TYPE::Attribute: _doSetattr(ast_cast(target), val, unw_info); @@ -1711,7 +1825,7 @@ class IRGeneratorImpl : public IRGenerator { } } - void doAssert(AST_Assert* node, UnwindInfo unw_info) { + void doAssert(AST_Assert* node, const UnwindInfo& unw_info) { // cfg translates all asserts into only 'assert 0' on the failing path. AST_expr* test = node->test; assert(test->type == AST_TYPE::Num); @@ -1740,7 +1854,7 @@ class IRGeneratorImpl : public IRGenerator { call.setDoesNotReturn(); } - void doAssign(AST_Assign* node, UnwindInfo unw_info) { + void doAssign(AST_Assign* node, const UnwindInfo& unw_info) { CompilerVariable* val = evalExpr(node->value, unw_info); for (int i = 0; i < node->targets.size(); i++) { @@ -1749,7 +1863,7 @@ class IRGeneratorImpl : public IRGenerator { val->decvref(emitter); } - void doDelete(AST_Delete* node, UnwindInfo unw_info) { + void doDelete(AST_Delete* node, const UnwindInfo& unw_info) { for (AST_expr* target : node->targets) { switch (target->type) { case AST_TYPE::Subscript: @@ -1769,7 +1883,7 @@ class IRGeneratorImpl : public IRGenerator { } // invoke delitem in objmodel.cpp, which will invoke the listDelitem of list - void _doDelitem(AST_Subscript* target, UnwindInfo unw_info) { + void _doDelitem(AST_Subscript* target, const UnwindInfo& unw_info) { CompilerVariable* tget = evalExpr(target->value, unw_info); CompilerVariable* slice = evalExpr(target->slice, unw_info); @@ -1795,12 +1909,12 @@ class IRGeneratorImpl : public IRGenerator { converted_slice->decvref(emitter); } - void _doDelAttr(AST_Attribute* node, UnwindInfo unw_info) { + void _doDelAttr(AST_Attribute* node, const UnwindInfo& unw_info) { CompilerVariable* value = evalExpr(node->value, unw_info); value->delattr(emitter, getEmptyOpInfo(unw_info), node->attr.getBox()); } - void _doDelName(AST_Name* target, UnwindInfo unw_info) { + void _doDelName(AST_Name* target, const UnwindInfo& unw_info) { auto scope_info = irstate->getScopeInfo(); ScopeInfo::VarScopeType vst = scope_info->getScopeTypeOfName(target->id); if (vst == ScopeInfo::VarScopeType::GLOBAL) { @@ -1845,7 +1959,7 @@ class IRGeneratorImpl : public IRGenerator { symbol_table.erase(target->id); } - void doExec(AST_Exec* node, UnwindInfo unw_info) { + void doExec(AST_Exec* node, const UnwindInfo& unw_info) { CompilerVariable* body = evalExpr(node->body, unw_info); llvm::Value* vbody = body->makeConverted(emitter, body->getBoxType())->getValue(); body->decvref(emitter); @@ -1873,7 +1987,7 @@ class IRGeneratorImpl : public IRGenerator { { vbody, vglobals, vlocals, getConstantInt(irstate->getSourceInfo()->future_flags, g.i32) }); } - void doPrint(AST_Print* node, UnwindInfo unw_info) { + void doPrint(AST_Print* node, const UnwindInfo& unw_info) { ConcreteCompilerVariable* dest = NULL; if (node->dest) { auto d = evalExpr(node->dest, unw_info); @@ -1945,8 +2059,8 @@ class IRGeneratorImpl : public IRGenerator { dest->decvref(emitter); } - void doReturn(AST_Return* node, UnwindInfo unw_info) { - assert(!unw_info.needsInvoke()); + void doReturn(AST_Return* node, const UnwindInfo& unw_info) { + assert(!unw_info.hasHandler()); CompilerVariable* val; if (node->value == NULL) { @@ -1984,8 +2098,8 @@ class IRGeneratorImpl : public IRGenerator { emitter.getBuilder()->CreateRet(rtn->getValue()); } - void doBranch(AST_Branch* node, UnwindInfo unw_info) { - assert(!unw_info.needsInvoke()); + void doBranch(AST_Branch* node, const UnwindInfo& unw_info) { + assert(!unw_info.hasHandler()); assert(node->iftrue->idx > myblock->idx); assert(node->iffalse->idx > myblock->idx); @@ -2007,7 +2121,7 @@ class IRGeneratorImpl : public IRGenerator { emitter.getBuilder()->CreateCondBr(v, iftrue, iffalse); } - void doExpr(AST_Expr* node, UnwindInfo unw_info) { + void doExpr(AST_Expr* node, const UnwindInfo& unw_info) { CompilerVariable* var = evalExpr(node->value, unw_info); var->decvref(emitter); @@ -2179,7 +2293,7 @@ class IRGeneratorImpl : public IRGenerator { emitter.getBuilder()->SetInsertPoint(starting_block); } - void doJump(AST_Jump* node, UnwindInfo unw_info) { + void doJump(AST_Jump* node, const UnwindInfo& unw_info) { endBlock(FINISHED); llvm::BasicBlock* target = entry_blocks[node->target]; @@ -2192,7 +2306,7 @@ class IRGeneratorImpl : public IRGenerator { } } - void doRaise(AST_Raise* node, UnwindInfo unw_info) { + void doRaise(AST_Raise* node, const UnwindInfo& unw_info) { // It looks like ommitting the second and third arguments are equivalent to passing None, // but ommitting the first argument is *not* the same as passing None. @@ -2225,7 +2339,7 @@ class IRGeneratorImpl : public IRGenerator { endBlock(DEAD); } - void doStmt(AST_stmt* node, UnwindInfo unw_info) { + void doStmt(AST_stmt* node, const UnwindInfo& unw_info) { // printf("%d stmt: %d\n", node->type, node->lineno); if (node->lineno) { emitter.getBuilder()->SetCurrentDebugLocation( @@ -2267,21 +2381,27 @@ class IRGeneratorImpl : public IRGenerator { doPrint(ast_cast(node), unw_info); break; case AST_TYPE::Return: - assert(!unw_info.needsInvoke()); + assert(!unw_info.hasHandler()); doReturn(ast_cast(node), unw_info); break; case AST_TYPE::Branch: - assert(!unw_info.needsInvoke()); + assert(!unw_info.hasHandler()); doBranch(ast_cast(node), unw_info); break; case AST_TYPE::Jump: - assert(!unw_info.needsInvoke()); + assert(!unw_info.hasHandler()); doJump(ast_cast(node), unw_info); break; case AST_TYPE::Invoke: { - assert(!unw_info.needsInvoke()); + assert(!unw_info.hasHandler()); AST_Invoke* invoke = ast_cast(node); - doStmt(invoke->stmt, UnwindInfo(node, entry_blocks[invoke->exc_dest])); + + ExceptionStyle landingpad_style = irstate->getLandingpadStyle(invoke); + + if (landingpad_style == CXX) + doStmt(invoke->stmt, UnwindInfo(node, NULL, entry_blocks[invoke->exc_dest])); + else + doStmt(invoke->stmt, UnwindInfo(node, entry_blocks[invoke->exc_dest], NULL)); assert(state == RUNNING || state == DEAD); if (state == RUNNING) { @@ -2300,14 +2420,14 @@ class IRGeneratorImpl : public IRGenerator { } } - void loadArgument(InternedString name, ConcreteCompilerType* t, llvm::Value* v, UnwindInfo unw_info) { + void loadArgument(InternedString name, ConcreteCompilerType* t, llvm::Value* v, const UnwindInfo& unw_info) { assert(name.s() != FRAME_INFO_PTR_NAME); ConcreteCompilerVariable* var = unboxVar(t, v, false); _doSet(name, var, unw_info); var->decvref(emitter); } - void loadArgument(AST_expr* name, ConcreteCompilerType* t, llvm::Value* v, UnwindInfo unw_info) { + void loadArgument(AST_expr* name, ConcreteCompilerType* t, llvm::Value* v, const UnwindInfo& unw_info) { ConcreteCompilerVariable* var = unboxVar(t, v, false); _doSet(name, var, unw_info); var->decvref(emitter); @@ -2656,7 +2776,7 @@ class IRGeneratorImpl : public IRGenerator { doSafePoint(block->body[i]); #endif - doStmt(block->body[i], UnwindInfo(block->body[i], NULL)); + doStmt(block->body[i], UnwindInfo(block->body[i], NULL, NULL)); } if (VERBOSITY("irgenerator") >= 2) { // print ending symbol table printf(" %d fini:", block->idx); @@ -2669,7 +2789,7 @@ class IRGeneratorImpl : public IRGenerator { void doSafePoint(AST_stmt* next_statement) override { // Unwind info is always needed in allowGLReadPreemption if it has any chance of // running arbitrary code like finalizers. - emitter.createCall(UnwindInfo(next_statement, NULL), g.funcs.allowGLReadPreemption); + emitter.createCall(UnwindInfo(next_statement, NULL, NULL), g.funcs.allowGLReadPreemption); } }; diff --git a/src/codegen/irgen/irgenerator.h b/src/codegen/irgen/irgenerator.h index ed805f38f..f62030b05 100644 --- a/src/codegen/irgen/irgenerator.h +++ b/src/codegen/irgen/irgenerator.h @@ -17,6 +17,7 @@ #include +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/iterator_range.h" #include "llvm/IR/Instructions.h" @@ -33,6 +34,7 @@ class MDNode; namespace pyston { +class AST_Invoke; class CFGBlock; class GCBuilder; struct PatchpointInfo; @@ -70,6 +72,7 @@ class IRGenState { llvm::Value* frame_info_arg; int scratch_size; + llvm::DenseMap landingpad_styles; public: IRGenState(CLFunction* clfunc, CompiledFunction* cf, SourceInfo* source_info, std::unique_ptr phis, @@ -104,6 +107,9 @@ class IRGenState { ParamNames* getParamNames() { return param_names; } void setFrameInfoArgument(llvm::Value* v) { frame_info_arg = v; } + + ExceptionStyle getLandingpadStyle(AST_Invoke* invoke); + ExceptionStyle getLandingpadStyle(CFGBlock* block); }; // turns CFGBlocks into LLVM IR diff --git a/src/codegen/runtime_hooks.cpp b/src/codegen/runtime_hooks.cpp index e8fa22086..14529eceb 100644 --- a/src/codegen/runtime_hooks.cpp +++ b/src/codegen/runtime_hooks.cpp @@ -195,6 +195,7 @@ void initGlobalFuncs(GlobalState& g) { GET(createSet); GET(getattr); + GET(getattr_capi); GET(setattr); GET(delattr); GET(getitem); @@ -223,6 +224,8 @@ void initGlobalFuncs(GlobalState& g) { GET(unpackIntoArray); GET(raiseAttributeError); GET(raiseAttributeErrorStr); + GET(raiseAttributeErrorCapi); + GET(raiseAttributeErrorStrCapi); GET(raiseIndexErrorStr); GET(raiseNotIterableError); GET(assertNameDefined); @@ -270,6 +273,9 @@ void initGlobalFuncs(GlobalState& g) { g.funcs.__cxa_end_catch = addFunc((void*)__cxa_end_catch, g.void_); GET(raise0); GET(raise3); + GET(PyErr_Fetch); + GET(PyErr_NormalizeException); + GET(capiExcCaughtInJit); GET(deopt); GET(div_float_float); diff --git a/src/codegen/runtime_hooks.h b/src/codegen/runtime_hooks.h index 7ad9b8e5c..19c0745d9 100644 --- a/src/codegen/runtime_hooks.h +++ b/src/codegen/runtime_hooks.h @@ -35,12 +35,13 @@ struct GlobalFuncs { llvm::Value* boxInt, *unboxInt, *boxFloat, *unboxFloat, *boxCLFunction, *unboxCLFunction, *boxInstanceMethod, *boxBool, *unboxBool, *createTuple, *createDict, *createList, *createSlice, *createUserClass, *createClosure, *createGenerator, *createSet; - llvm::Value* getattr, *setattr, *delattr, *delitem, *delGlobal, *nonzero, *binop, *compare, *augbinop, *unboxedLen, - *getitem, *getclsattr, *getGlobal, *setitem, *unaryop, *import, *importFrom, *importStar, *repr, *str, - *strOrUnicode, *exceptionMatches, *yield, *getiterHelper, *hasnext; + llvm::Value* getattr, *getattr_capi, *setattr, *delattr, *delitem, *delGlobal, *nonzero, *binop, *compare, + *augbinop, *unboxedLen, *getitem, *getclsattr, *getGlobal, *setitem, *unaryop, *import, *importFrom, + *importStar, *repr, *str, *strOrUnicode, *exceptionMatches, *yield, *getiterHelper, *hasnext; - llvm::Value* unpackIntoArray, *raiseAttributeError, *raiseAttributeErrorStr, *raiseNotIterableError, - *raiseIndexErrorStr, *assertNameDefined, *assertFail, *assertFailDerefNameDefined; + llvm::Value* unpackIntoArray, *raiseAttributeError, *raiseAttributeErrorStr, *raiseAttributeErrorCapi, + *raiseAttributeErrorStrCapi, *raiseNotIterableError, *raiseIndexErrorStr, *assertNameDefined, *assertFail, + *assertFailDerefNameDefined; llvm::Value* printFloat, *listAppendInternal, *getSysStdout; llvm::Value* runtimeCall0, *runtimeCall1, *runtimeCall2, *runtimeCall3, *runtimeCall, *runtimeCallN; llvm::Value* callattr0, *callattr1, *callattr2, *callattr3, *callattr, *callattrN; @@ -50,6 +51,7 @@ struct GlobalFuncs { llvm::Value* __cxa_end_catch; llvm::Value* raise0, *raise3; + llvm::Value* PyErr_Fetch, *PyErr_NormalizeException, *capiExcCaughtInJit; llvm::Value* deopt; llvm::Value* div_float_float, *floordiv_float_float, *mod_float_float, *pow_float_float; diff --git a/src/codegen/unwinding.cpp b/src/codegen/unwinding.cpp index 22b333a08..c02a113b2 100644 --- a/src/codegen/unwinding.cpp +++ b/src/codegen/unwinding.cpp @@ -603,6 +603,14 @@ static const LineInfo lineInfoForFrame(PythonFrameIteratorImpl* frame_it) { return LineInfo(current_stmt->lineno, current_stmt->col_offset, source->fn, source->getName()); } +extern "C" void capiExcCaughtInJit(AST_stmt* stmt, void* _source_info) { + SourceInfo* source = static_cast(_source_info); + // TODO: handle reraise (currently on the ExcInfo object) + PyThreadState* tstate = PyThreadState_GET(); + BoxedTraceback::here(LineInfo(stmt->lineno, stmt->col_offset, source->fn, source->getName()), + &tstate->curexc_traceback); +} + void exceptionCaughtInInterpreter(LineInfo line_info, ExcInfo* exc_info) { static StatCounter frames_unwound("num_frames_unwound_python"); frames_unwound.log(); diff --git a/src/core/stats.cpp b/src/core/stats.cpp index ee3b1e1f5..8b18afa00 100644 --- a/src/core/stats.cpp +++ b/src/core/stats.cpp @@ -104,9 +104,6 @@ void Stats::clear() { } void Stats::startEstimatingCPUFreq() { - if (!Stats::enabled) - return; - clock_gettime(CLOCK_REALTIME, &Stats::start_ts); Stats::start_tick = getCPUTicks(); } diff --git a/src/core/types.h b/src/core/types.h index 7590fefb2..72920fd4f 100644 --- a/src/core/types.h +++ b/src/core/types.h @@ -68,32 +68,43 @@ enum class EffortLevel { MAXIMAL = 3, }; -namespace ExceptionStyle { enum ExceptionStyle { CAPI, CXX, }; -}; -template struct ExceptionSwitchableFunction { +template struct ExceptionSwitchable { public: - typedef R (*FTy)(Args...); - FTy capi_ptr; - FTy cxx_ptr; + T capi_val; + T cxx_val; - ExceptionSwitchableFunction(FTy capi_ptr, FTy cxx_ptr) : capi_ptr(capi_ptr), cxx_ptr(cxx_ptr) {} + ExceptionSwitchable() : capi_val(), cxx_val() {} + ExceptionSwitchable(T capi_val, T cxx_val) : capi_val(std::move(capi_val)), cxx_val(std::move(cxx_val)) {} - template FTy get() { - if (S == ExceptionStyle::CAPI) - return capi_ptr; + template T get() { + if (S == CAPI) + return capi_val; else - return cxx_ptr; + return cxx_val; } - template R call(Args... args) noexcept(S == ExceptionStyle::CAPI) { - return get()(args...); + + T get(ExceptionStyle S) { + if (S == CAPI) + return capi_val; + else + return cxx_val; } }; +template +struct ExceptionSwitchableFunction : public ExceptionSwitchable { +public: + typedef R (*FTy)(Args...); + ExceptionSwitchableFunction(FTy capi_ptr, FTy cxx_ptr) : ExceptionSwitchable(capi_ptr, cxx_ptr) {} + + template R call(Args... args) noexcept(S == CAPI) { return this->template get()(args...); } +}; + class CompilerType; template class ValuedCompilerType; typedef ValuedCompilerType ConcreteCompilerType; @@ -283,7 +294,7 @@ struct CompiledFunction { int code_size; EffortLevel effort; - ExceptionStyle::ExceptionStyle exception_style; + ExceptionStyle exception_style; int64_t times_called, times_speculation_failed; ICInvalidator dependent_callsites; @@ -293,7 +304,7 @@ struct CompiledFunction { std::vector ics; CompiledFunction(llvm::Function* func, FunctionSpecialization* spec, void* code, EffortLevel effort, - ExceptionStyle::ExceptionStyle exception_style, const OSREntryDescriptor* entry_descriptor); + ExceptionStyle exception_style, const OSREntryDescriptor* entry_descriptor); ConcreteCompilerType* getReturnType(); @@ -414,15 +425,12 @@ CLFunction* createRTFunction(int num_args, int num_defaults, bool takes_varargs, const ParamNames& param_names = ParamNames::empty()); CLFunction* boxRTFunction(void* f, ConcreteCompilerType* rtn_type, int nargs, int num_defaults, bool takes_varargs, bool takes_kwargs, const ParamNames& param_names = ParamNames::empty(), - ExceptionStyle::ExceptionStyle exception_style = ExceptionStyle::CXX); + ExceptionStyle exception_style = CXX); CLFunction* boxRTFunction(void* f, ConcreteCompilerType* rtn_type, int nargs, - const ParamNames& param_names = ParamNames::empty(), - ExceptionStyle::ExceptionStyle exception_style = ExceptionStyle::CXX); -void addRTFunction(CLFunction* cf, void* f, ConcreteCompilerType* rtn_type, - ExceptionStyle::ExceptionStyle exception_style = ExceptionStyle::CXX); + const ParamNames& param_names = ParamNames::empty(), ExceptionStyle exception_style = CXX); +void addRTFunction(CLFunction* cf, void* f, ConcreteCompilerType* rtn_type, ExceptionStyle exception_style = CXX); void addRTFunction(CLFunction* cf, void* f, ConcreteCompilerType* rtn_type, - const std::vector& arg_types, - ExceptionStyle::ExceptionStyle exception_style = ExceptionStyle::CXX); + const std::vector& arg_types, ExceptionStyle exception_style = CXX); CLFunction* unboxRTFunction(Box*); // Compiles a new version of the function with the given signature and adds it to the list; diff --git a/src/runtime/builtin_modules/builtins.cpp b/src/runtime/builtin_modules/builtins.cpp index 29ab19528..7e7c6383b 100644 --- a/src/runtime/builtin_modules/builtins.cpp +++ b/src/runtime/builtin_modules/builtins.cpp @@ -1382,7 +1382,7 @@ void setupBuiltins() { builtins_module->giveAttr("repr", repr_obj); auto len_func = boxRTFunction((void*)len, UNKNOWN, 1); - len_func->internal_callable.cxx_ptr = lenCallInternal; + len_func->internal_callable.cxx_val = lenCallInternal; len_obj = new BoxedBuiltinFunctionOrMethod(len_func, "len"); builtins_module->giveAttr("len", len_obj); diff --git a/src/runtime/capi.cpp b/src/runtime/capi.cpp index 262ba75e8..bed3733c0 100644 --- a/src/runtime/capi.cpp +++ b/src/runtime/capi.cpp @@ -786,6 +786,11 @@ void setCAPIException(const ExcInfo& e) { cur_thread_state.curexc_traceback = e.traceback; } +void ensureCAPIExceptionSet() { + if (!cur_thread_state.curexc_type) + PyErr_SetString(SystemError, "error return without exception set"); +} + void throwCAPIException() { checkAndThrowCAPIException(); raiseExcHelper(SystemError, "error return without exception set"); diff --git a/src/runtime/dict.cpp b/src/runtime/dict.cpp index 82265efcf..1f38f4ad2 100644 --- a/src/runtime/dict.cpp +++ b/src/runtime/dict.cpp @@ -27,9 +27,6 @@ namespace pyston { -using namespace pyston::ExceptionStyle; -using pyston::ExceptionStyle::ExceptionStyle; - Box* dictRepr(BoxedDict* self) { std::vector chars; chars.push_back('{'); diff --git a/src/runtime/inline/link_forcer.cpp b/src/runtime/inline/link_forcer.cpp index 1c40b08d0..4414497e6 100644 --- a/src/runtime/inline/link_forcer.cpp +++ b/src/runtime/inline/link_forcer.cpp @@ -74,6 +74,7 @@ void force() { FORCE(decodeUTF8StringPtr); FORCE(getattr); + FORCE(getattr_capi); FORCE(setattr); FORCE(delattr); FORCE(nonzero); @@ -101,6 +102,8 @@ void force() { FORCE(unpackIntoArray); FORCE(raiseAttributeError); FORCE(raiseAttributeErrorStr); + FORCE(raiseAttributeErrorCapi); + FORCE(raiseAttributeErrorStrCapi); FORCE(raiseIndexErrorStr); FORCE(raiseNotIterableError); FORCE(assertNameDefined); @@ -117,6 +120,9 @@ void force() { FORCE(raise0); FORCE(raise3); + FORCE(PyErr_Fetch); + FORCE(PyErr_NormalizeException); + FORCE(capiExcCaughtInJit); FORCE(deopt); FORCE(div_i64_i64); diff --git a/src/runtime/inline/list.cpp b/src/runtime/inline/list.cpp index 64b33e60f..0db58b791 100644 --- a/src/runtime/inline/list.cpp +++ b/src/runtime/inline/list.cpp @@ -22,9 +22,6 @@ namespace pyston { -using namespace pyston::ExceptionStyle; -using pyston::ExceptionStyle::ExceptionStyle; - BoxedListIterator::BoxedListIterator(BoxedList* l, int start) : l(l), pos(start) { } @@ -68,7 +65,7 @@ i1 listiterHasnextUnboxed(Box* s) { return ans; } -template Box* listiterNext(Box* s) noexcept(S == CAPI) { +template Box* listiterNext(Box* s) noexcept(S == CAPI) { assert(s->cls == list_iterator_cls); BoxedListIterator* self = static_cast(s); diff --git a/src/runtime/list.cpp b/src/runtime/list.cpp index e5dd83df2..748ce3ee2 100644 --- a/src/runtime/list.cpp +++ b/src/runtime/list.cpp @@ -704,7 +704,7 @@ class PyCmpComparer { public: PyCmpComparer(Box* cmp) : cmp(cmp) {} bool operator()(Box* lhs, Box* rhs) { - Box* r = runtimeCallInternal(cmp, NULL, ArgPassSpec(2), lhs, rhs, NULL, NULL, NULL); + Box* r = runtimeCallInternal(cmp, NULL, ArgPassSpec(2), lhs, rhs, NULL, NULL, NULL); if (!isSubclass(r->cls, int_cls)) raiseExcHelper(TypeError, "comparison function must return int, not %.200s", r->cls->tp_name); return static_cast(r)->n < 0; @@ -1170,8 +1170,8 @@ void setupList() { list_iterator_cls->giveAttr( "__iter__", new BoxedFunction(boxRTFunction((void*)listIterIter, typeFromClass(list_iterator_cls), 1))); - CLFunction* listiter_next = boxRTFunction((void*)listiterNext, UNKNOWN, 1); - addRTFunction(listiter_next, (void*)listiterNext, UNKNOWN, ExceptionStyle::CAPI); + CLFunction* listiter_next = boxRTFunction((void*)listiterNext, UNKNOWN, 1); + addRTFunction(listiter_next, (void*)listiterNext, UNKNOWN, CAPI); list_iterator_cls->giveAttr("next", new BoxedFunction(listiter_next)); list_iterator_cls->freeze(); diff --git a/src/runtime/list.h b/src/runtime/list.h index 794dfad20..7e4164551 100644 --- a/src/runtime/list.h +++ b/src/runtime/list.h @@ -35,7 +35,7 @@ Box* listIter(Box* self); Box* listIterIter(Box* self); Box* listiterHasnext(Box* self); i1 listiterHasnextUnboxed(Box* self); -template Box* listiterNext(Box* self) noexcept(S == ExceptionStyle::CAPI); +template Box* listiterNext(Box* self) noexcept(S == CAPI); Box* listReversed(Box* self); Box* listreviterHasnext(Box* self); i1 listreviterHasnextUnboxed(Box* self); diff --git a/src/runtime/objmodel.cpp b/src/runtime/objmodel.cpp index 4a82c2feb..f77d1d122 100644 --- a/src/runtime/objmodel.cpp +++ b/src/runtime/objmodel.cpp @@ -60,9 +60,6 @@ namespace pyston { -using namespace pyston::ExceptionStyle; -using pyston::ExceptionStyle::ExceptionStyle; - static const std::string iter_str("__iter__"); static const std::string new_str("__new__"); static const std::string none_str("None"); @@ -76,20 +73,20 @@ void REWRITE_ABORTED(const char* reason) { #define REWRITE_ABORTED(reason) ((void)(reason)) #endif -template +template static inline Box* runtimeCallInternal0(Box* obj, CallRewriteArgs* rewrite_args, ArgPassSpec argspec) { return runtimeCallInternal(obj, rewrite_args, argspec, NULL, NULL, NULL, NULL, NULL); } -template +template static inline Box* runtimeCallInternal1(Box* obj, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1) { return runtimeCallInternal(obj, rewrite_args, argspec, arg1, NULL, NULL, NULL, NULL); } -template +template static inline Box* runtimeCallInternal2(Box* obj, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2) { return runtimeCallInternal(obj, rewrite_args, argspec, arg1, arg2, NULL, NULL, NULL); } -template +template static inline Box* runtimeCallInternal3(Box* obj, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3) { return runtimeCallInternal(obj, rewrite_args, argspec, arg1, arg2, arg3, NULL, NULL); @@ -274,7 +271,12 @@ extern "C" void assertFailDerefNameDefined(const char* name) { extern "C" void raiseAttributeErrorStr(const char* typeName, llvm::StringRef attr) { assert(attr.data()[attr.size()] == '\0'); - raiseExcHelper(AttributeError, "'%s' object has no attribute '%s'", typeName, attr); + raiseExcHelper(AttributeError, "'%s' object has no attribute '%s'", typeName, attr.data()); +} + +extern "C" void raiseAttributeErrorStrCapi(const char* typeName, llvm::StringRef attr) noexcept { + assert(attr.data()[attr.size()] == '\0'); + PyErr_Format(AttributeError, "'%s' object has no attribute '%s'", typeName, attr.data()); } extern "C" void raiseAttributeError(Box* obj, llvm::StringRef attr) { @@ -288,6 +290,17 @@ extern "C" void raiseAttributeError(Box* obj, llvm::StringRef attr) { } } +extern "C" void raiseAttributeErrorCapi(Box* obj, llvm::StringRef attr) noexcept { + if (obj->cls == type_cls) { + // Slightly different error message: + assert(attr.data()[attr.size()] == '\0'); + PyErr_Format(AttributeError, "type object '%s' has no attribute '%s'", + getNameOfClass(static_cast(obj)), attr.data()); + } else { + raiseAttributeErrorStrCapi(getTypeName(obj), attr); + } +} + extern "C" void raiseIndexErrorStr(const char* typeName) { raiseExcHelper(IndexError, "%s index out of range", typeName); } @@ -1342,16 +1355,18 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS return NULL; } -template +// Helper function: make sure that a capi function either returned a non-error value, or +// it set an exception. +static void ensureValidCapiReturn(Box* r) { + if (!r) + ensureCAPIExceptionSet(); +} + +template Box* getattrInternalEx(Box* obj, BoxedString* attr, GetattrRewriteArgs* rewrite_args, bool cls_only, bool for_call, - Box** bind_obj_out, RewriterVar** r_bind_obj_out) noexcept(S == ExceptionStyle::CAPI) { + Box** bind_obj_out, RewriterVar** r_bind_obj_out) noexcept(S == CAPI) { assert(gc::isValidGCObject(attr)); - if (S == CAPI) { - assert(!rewrite_args && "implement me"); - rewrite_args = NULL; - } - if (!cls_only) { BoxedClass* cls = obj->cls; @@ -1363,23 +1378,19 @@ Box* getattrInternalEx(Box* obj, BoxedString* attr, GetattrRewriteArgs* rewrite_ if (obj->cls->tp_getattro && obj->cls->tp_getattro != PyObject_GenericGetAttr) { STAT_TIMER(t0, "us_timer_slowpath_tpgetattro", 10); - if (obj->cls->tp_getattro == slot_tp_getattr_hook) { - if (S == CAPI) { - assert(!rewrite_args && "implement me"); - return obj->cls->tp_getattro(obj, attr); - } else { - return slotTpGetattrHookInternal(obj, attr, rewrite_args); - } + if (obj->cls->tp_getattro == slot_tp_getattr_hook && S == CXX) { + return slotTpGetattrHookInternal(obj, attr, rewrite_args); } Box* r = obj->cls->tp_getattro(obj, attr); - if (S == CAPI) { - assert(!rewrite_args && "implement me"); - return r; - } - if (!r) - throwCAPIException(); + if (!r) { + if (S == CAPI) { + ensureCAPIExceptionSet(); + return r; + } else + throwCAPIException(); + } // If attr is immortal, then we are free to write an embedded reference to it. // Immortal are (unfortunately) common right now, so this is an easy way to get @@ -1388,7 +1399,11 @@ Box* getattrInternalEx(Box* obj, BoxedString* attr, GetattrRewriteArgs* rewrite_ if (rewrite_args && attr->interned_state == SSTATE_INTERNED_IMMORTAL) { auto r_box = rewrite_args->rewriter->loadConst((intptr_t)attr); auto r_rtn = rewrite_args->rewriter->call(true, (void*)obj->cls->tp_getattro, rewrite_args->obj, r_box); - rewrite_args->rewriter->call(true, (void*)checkAndThrowCAPIException); + + if (S == CXX) + rewrite_args->rewriter->call(true, (void*)checkAndThrowCAPIException); + else + rewrite_args->rewriter->call(false, (void*)ensureValidCapiReturn, r_rtn); rewrite_args->out_rtn = r_rtn; rewrite_args->out_success = true; @@ -1406,9 +1421,13 @@ Box* getattrInternalEx(Box* obj, BoxedString* attr, GetattrRewriteArgs* rewrite_ assert(attr->data()[attr->size()] == '\0'); + rewrite_args = NULL; + Box* r = obj->cls->tp_getattr(obj, const_cast(attr->data())); if (S == CAPI) { + if (!r) + ensureCAPIExceptionSet(); return r; } else { if (!r) @@ -1848,9 +1867,8 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew return NULL; } -template -Box* getattrInternal(Box* obj, BoxedString* attr, - GetattrRewriteArgs* rewrite_args) noexcept(S == ExceptionStyle::CAPI) { +template +Box* getattrInternal(Box* obj, BoxedString* attr, GetattrRewriteArgs* rewrite_args) noexcept(S == CAPI) { return getattrInternalEx(obj, attr, rewrite_args, /* cls_only */ false, /* for_call */ false, NULL, NULL); @@ -1880,7 +1898,7 @@ Box* getattrMaybeNonstring(Box* obj, Box* attr) { return r; } -extern "C" Box* getattr(Box* obj, BoxedString* attr) { +template Box* _getattrEntry(Box* obj, BoxedString* attr, void* return_addr) noexcept(S == CAPI) { STAT_TIMER(t0, "us_timer_slowpath_getattr", 10); static StatCounter slowpath_getattr("slowpath_getattr"); @@ -1896,14 +1914,13 @@ extern "C" Box* getattr(Box* obj, BoxedString* attr) { #endif } - std::unique_ptr rewriter( - Rewriter::createRewriter(__builtin_extract_return_addr(__builtin_return_address(0)), 2, "getattr")); + std::unique_ptr rewriter(Rewriter::createRewriter(return_addr, 2, "getattr")); #if 0 && STAT_TIMERS static uint64_t* st_id = Stats::getStatCounter("us_timer_slowpath_getattr_patchable"); static uint64_t* st_id_nopatch = Stats::getStatCounter("us_timer_slowpath_getattr_nopatch"); static uint64_t* st_id_megamorphic = Stats::getStatCounter("us_timer_slowpath_getattr_megamorphic"); - ICInfo* icinfo = getICInfo(__builtin_extract_return_addr(__builtin_return_address(0))); + ICInfo* icinfo = getICInfo(return_addr); uint64_t* counter; if (!icinfo) counter = st_id_nopatch; @@ -1931,15 +1948,22 @@ extern "C" Box* getattr(Box* obj, BoxedString* attr) { else dest = rewriter->getReturnDestination(); GetattrRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0), dest); - val = getattrInternal(obj, attr, &rewrite_args); + val = getattrInternal(obj, attr, &rewrite_args); if (rewrite_args.out_success) { if (!val) { if (attr->interned_state == SSTATE_INTERNED_IMMORTAL) { - rewriter->call(true, (void*)raiseAttributeError, rewriter->getArg(0), - rewriter->loadConst((intptr_t)attr->data(), Location::forArg(1)), - rewriter->loadConst(attr->size(), Location::forArg(2))); - rewriter->commit(); + if (S == CXX) { + rewriter->call(true, (void*)raiseAttributeError, rewriter->getArg(0), + rewriter->loadConst((intptr_t)attr->data(), Location::forArg(1)), + rewriter->loadConst(attr->size(), Location::forArg(2))); + rewriter->commit(); + } else if (S == CAPI && !PyErr_Occurred()) { + rewriter->call(true, (void*)raiseAttributeErrorCapi, rewriter->getArg(0), + rewriter->loadConst((intptr_t)attr->data(), Location::forArg(1)), + rewriter->loadConst(attr->size(), Location::forArg(2))); + rewriter->commitReturning(rewriter->loadConst(0, rewriter->getReturnDestination())); + } } } else if (recorder) { RewriterVar* record_rtn = rewriter->call(false, (void*)recordType, @@ -1953,14 +1977,27 @@ extern "C" Box* getattr(Box* obj, BoxedString* attr) { } } } else { - val = getattrInternal(obj, attr, NULL); + val = getattrInternal(obj, attr, NULL); } - if (val) { + if (val) return val; + + if (S == CAPI) { + if (!PyErr_Occurred()) + raiseAttributeErrorCapi(obj, attr->s()); + return NULL; + } else { + raiseAttributeError(obj, attr->s()); } +} - raiseAttributeError(obj, attr->s()); +extern "C" Box* getattr_capi(Box* obj, BoxedString* attr) noexcept { + return _getattrEntry(obj, attr, __builtin_extract_return_addr(__builtin_return_address(0))); +} + +extern "C" Box* getattr(Box* obj, BoxedString* attr) { + return _getattrEntry(obj, attr, __builtin_extract_return_addr(__builtin_return_address(0))); } bool dataDescriptorSetSpecialCases(Box* obj, Box* val, Box* descr, SetattrRewriteArgs* rewrite_args, @@ -2458,8 +2495,7 @@ extern "C" BoxedInt* hash(Box* obj) { return new BoxedInt(r); } -template -BoxedInt* lenInternal(Box* obj, LenRewriteArgs* rewrite_args) noexcept(S == ExceptionStyle::CAPI) { +template BoxedInt* lenInternal(Box* obj, LenRewriteArgs* rewrite_args) noexcept(S == CAPI) { static BoxedString* len_str = internStringImmortal("__len__"); if (S == CAPI) { @@ -2793,7 +2829,7 @@ static inline RewriterVar* getArg(int idx, CallRewriteArgs* rewrite_args) { } static StatCounter slowpath_pickversion("slowpath_pickversion"); -static CompiledFunction* pickVersion(CLFunction* f, enum ExceptionStyle S, int num_output_args, Box* oarg1, Box* oarg2, +static CompiledFunction* pickVersion(CLFunction* f, ExceptionStyle S, int num_output_args, Box* oarg1, Box* oarg2, Box* oarg3, Box** oargs) { LOCK_REGION(codegen_rwlock.asWrite()); @@ -3256,7 +3292,7 @@ void rearrangeArguments(ParamReceiveSpec paramspec, const ParamNames* param_name } static StatCounter slowpath_callfunc("slowpath_callfunc"); -template +template Box* callFunc(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3, Box** args, const std::vector* keyword_names) noexcept(S == CAPI) { #if STAT_TIMERS @@ -3389,7 +3425,7 @@ Box* callFunc(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ArgPassSpe return res; } -template +template static Box* callChosenCF(CompiledFunction* chosen_cf, BoxedClosure* closure, BoxedGenerator* generator, Box* oarg1, Box* oarg2, Box* oarg3, Box** oargs) noexcept(S == CAPI) { if (S != chosen_cf->exception_style) { @@ -3431,7 +3467,7 @@ static Box* astInterpretHelper(CLFunction* f, int num_args, BoxedClosure* closur return astInterpretFunction(f, num_args, closure, generator, globals, arg1, arg2, arg3, (Box**)args); } -template +template Box* callCLFunc(CLFunction* f, CallRewriteArgs* rewrite_args, int num_output_args, BoxedClosure* closure, BoxedGenerator* generator, Box* globals, Box* oarg1, Box* oarg2, Box* oarg3, Box** oargs) noexcept(S == CAPI) { @@ -3543,7 +3579,7 @@ template Box* callCLFunc(CLFunction* f, CallRewriteArgs* rewrite_args, int template Box* callCLFunc(CLFunction* f, CallRewriteArgs* rewrite_args, int num_output_args, BoxedClosure* closure, BoxedGenerator* generator, Box* globals, Box* oarg1, Box* oarg2, Box* oarg3, Box** oargs); -template +template Box* runtimeCallInternal(Box* obj, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3, Box** args, const std::vector* keyword_names) noexcept(S == CAPI) { int npassed_args = argspec.totalPassed(); @@ -4416,8 +4452,8 @@ Box* callItemOrSliceAttr(Box* target, BoxedString* item_str, BoxedString* slice_ } } -template -Box* getitemInternal(Box* target, Box* slice, GetitemRewriteArgs* rewrite_args) noexcept(S == ExceptionStyle::CAPI) { +template +Box* getitemInternal(Box* target, Box* slice, GetitemRewriteArgs* rewrite_args) noexcept(S == CAPI) { if (S == CAPI) { assert(!rewrite_args && "implement me"); rewrite_args = NULL; diff --git a/src/runtime/objmodel.h b/src/runtime/objmodel.h index f7bbfbcfe..2bbb80f68 100644 --- a/src/runtime/objmodel.h +++ b/src/runtime/objmodel.h @@ -55,6 +55,7 @@ extern "C" bool softspace(Box* b, bool newval); extern "C" void printHelper(Box* dest, Box* var, bool nl); extern "C" void my_assert(bool b); extern "C" Box* getattr(Box* obj, BoxedString* attr); +extern "C" Box* getattr_capi(Box* obj, BoxedString* attr) noexcept; extern "C" Box* getattrMaybeNonstring(Box* obj, Box* attr); extern "C" void setattr(Box* obj, BoxedString* attr, Box* attr_val); extern "C" void setattrMaybeNonstring(Box* obj, Box* attr, Box* attr_val); @@ -107,25 +108,22 @@ struct BinopRewriteArgs; extern "C" Box* binopInternal(Box* lhs, Box* rhs, int op_type, bool inplace, BinopRewriteArgs* rewrite_args); struct CallRewriteArgs; -template +template Box* runtimeCallInternal(Box* obj, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3, - Box** args, - const std::vector* keyword_names) noexcept(S == ExceptionStyle::CAPI); + Box** args, const std::vector* keyword_names) noexcept(S == CAPI); struct GetitemRewriteArgs; -template -Box* getitemInternal(Box* target, Box* slice, GetitemRewriteArgs* rewrite_args) noexcept(S == ExceptionStyle::CAPI); +template +Box* getitemInternal(Box* target, Box* slice, GetitemRewriteArgs* rewrite_args) noexcept(S == CAPI); struct LenRewriteArgs; -template -BoxedInt* lenInternal(Box* obj, LenRewriteArgs* rewrite_args) noexcept(S == ExceptionStyle::CAPI); +template BoxedInt* lenInternal(Box* obj, LenRewriteArgs* rewrite_args) noexcept(S == CAPI); Box* lenCallInternal(BoxedFunctionBase* f, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3, Box** args, const std::vector* keyword_names); -template +template Box* callFunc(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* arg1, Box* arg2, - Box* arg3, Box** args, - const std::vector* keyword_names) noexcept(S == ExceptionStyle::CAPI); + Box* arg3, Box** args, const std::vector* keyword_names) noexcept(S == CAPI); enum LookupScope { CLASS_ONLY = 1, @@ -141,8 +139,8 @@ Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs* rewrit // This is the equivalent of PyObject_GetAttr. Unlike getattrInternalGeneric, it checks for custom __getattr__ or // __getattribute__ methods. -template -Box* getattrInternal(Box* obj, BoxedString* attr, GetattrRewriteArgs* rewrite_args) noexcept(S == ExceptionStyle::CAPI); +template +Box* getattrInternal(Box* obj, BoxedString* attr, GetattrRewriteArgs* rewrite_args) noexcept(S == CAPI); // This is the equivalent of PyObject_GenericGetAttr, which performs the default lookup rules for getattr() (check for // data descriptor, check for instance attribute, check for non-data descriptor). It does not check for __getattr__ or @@ -156,6 +154,8 @@ Box* typeLookup(BoxedClass* cls, BoxedString* attr, GetattrRewriteArgs* rewrite_ extern "C" void raiseAttributeErrorStr(const char* typeName, llvm::StringRef attr) __attribute__((__noreturn__)); extern "C" void raiseAttributeError(Box* obj, llvm::StringRef attr) __attribute__((__noreturn__)); +extern "C" void raiseAttributeErrorStrCapi(const char* typeName, llvm::StringRef attr) noexcept; +extern "C" void raiseAttributeErrorCapi(Box* obj, llvm::StringRef attr) noexcept; extern "C" void raiseNotIterableError(const char* typeName) __attribute__((__noreturn__)); extern "C" void raiseIndexErrorStr(const char* typeName) __attribute__((__noreturn__)); @@ -168,10 +168,10 @@ Box* typeNew(Box* cls, Box* arg1, Box* arg2, Box** _args); Box* processDescriptor(Box* obj, Box* inst, Box* owner); Box* processDescriptorOrNull(Box* obj, Box* inst, Box* owner); -template +template Box* callCLFunc(CLFunction* f, CallRewriteArgs* rewrite_args, int num_output_args, BoxedClosure* closure, BoxedGenerator* generator, Box* globals, Box* oarg1, Box* oarg2, Box* oarg3, - Box** oargs) noexcept(S == ExceptionStyle::CAPI); + Box** oargs) noexcept(S == CAPI); static const char* objectNewParameterTypeErrorMsg() { if (PYTHON_VERSION_HEX >= version_hex(2, 7, 4)) { diff --git a/src/runtime/types.cpp b/src/runtime/types.cpp index 3ba53d160..6f1f09143 100644 --- a/src/runtime/types.cpp +++ b/src/runtime/types.cpp @@ -639,7 +639,7 @@ static Box* typeCallInternal(BoxedFunctionBase* f, CallRewriteArgs* rewrite_args if (argspec.has_starargs || argspec.num_args == 0) { // Get callFunc to expand the arguments. // TODO: update this to use rearrangeArguments instead. - return callFunc(f, rewrite_args, argspec, arg1, arg2, arg3, args, keyword_names); + return callFunc(f, rewrite_args, argspec, arg1, arg2, arg3, args, keyword_names); } return typeCallInner(rewrite_args, argspec, arg1, arg2, arg3, args, keyword_names); @@ -997,8 +997,8 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo if (new_npassed_args >= 4) srewrite_args.args = rewrite_args->args; - made = runtimeCallInternal(new_attr, &srewrite_args, new_argspec, cls, arg2, arg3, - args, keyword_names); + made + = runtimeCallInternal(new_attr, &srewrite_args, new_argspec, cls, arg2, arg3, args, keyword_names); if (!srewrite_args.out_success) { rewrite_args = NULL; @@ -1015,8 +1015,7 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo if (cls->tp_new == object_cls->tp_new && cls->tp_init != object_cls->tp_init) made = objectNewNoArgs(cls); else - made = runtimeCallInternal(new_attr, NULL, new_argspec, cls, arg2, arg3, args, - keyword_names); + made = runtimeCallInternal(new_attr, NULL, new_argspec, cls, arg2, arg3, args, keyword_names); } assert(made); @@ -1066,8 +1065,8 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo // initrtn = callattrInternal(cls, _init_str, INST_ONLY, &srewrite_args, argspec, made, arg2, arg3, args, // keyword_names); - initrtn = runtimeCallInternal(init_attr, &srewrite_args, argspec, made, arg2, arg3, - args, keyword_names); + initrtn + = runtimeCallInternal(init_attr, &srewrite_args, argspec, made, arg2, arg3, args, keyword_names); if (!srewrite_args.out_success) { rewrite_args = NULL; @@ -1086,11 +1085,11 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo // If we weren't passed the args array, it's not safe to index into it if (passed <= 2) - initrtn = runtimeCallInternal(init_attr, NULL, init_argspec, arg2, arg3, NULL, - NULL, keyword_names); + initrtn + = runtimeCallInternal(init_attr, NULL, init_argspec, arg2, arg3, NULL, NULL, keyword_names); else - initrtn = runtimeCallInternal(init_attr, NULL, init_argspec, arg2, arg3, args[0], - &args[1], keyword_names); + initrtn = runtimeCallInternal(init_attr, NULL, init_argspec, arg2, arg3, args[0], &args[1], + keyword_names); } assertInitNone(initrtn); } else { @@ -1659,7 +1658,7 @@ static Box* instancemethodRepr(Box* b) { const char* sfuncname = "?", * sklassname = "?"; static BoxedString* name_str = internStringImmortal("__name__"); - funcname = getattrInternal(func, name_str, NULL); + funcname = getattrInternal(func, name_str, NULL); if (funcname != NULL) { if (!PyString_Check(funcname)) { @@ -1671,7 +1670,7 @@ static Box* instancemethodRepr(Box* b) { if (klass == NULL) { klassname = NULL; } else { - klassname = getattrInternal(klass, name_str, NULL); + klassname = getattrInternal(klass, name_str, NULL); if (klassname != NULL) { if (!PyString_Check(klassname)) { klassname = NULL; @@ -3419,7 +3418,7 @@ void setupRuntime() { // Punting on that until needed; hopefully by then we will have better Pyston slots support. auto typeCallObj = boxRTFunction((void*)typeCall, UNKNOWN, 1, 0, true, true); - typeCallObj->internal_callable.cxx_ptr = &typeCallInternal; + typeCallObj->internal_callable.cxx_val = &typeCallInternal; type_cls->giveAttr("__name__", new (pyston_getset_cls) BoxedGetsetDescriptor(typeName, typeSetName, NULL)); type_cls->giveAttr("__bases__", new (pyston_getset_cls) BoxedGetsetDescriptor(typeBases, typeSetBases, NULL)); diff --git a/src/runtime/types.h b/src/runtime/types.h index 619e4bc51..24d357dad 100644 --- a/src/runtime/types.h +++ b/src/runtime/types.h @@ -1000,6 +1000,7 @@ extern "C" PyObject* PystonType_GenericAlloc(BoxedClass* cls, Py_ssize_t nitems) void checkAndThrowCAPIException(); void throwCAPIException() __attribute__((noreturn)); +void ensureCAPIExceptionSet(); struct ExcInfo; void setCAPIException(const ExcInfo& e); diff --git a/test/tests/incremental_tb.py b/test/tests/incremental_tb.py index ec3911e5a..2b6ace6b3 100644 --- a/test/tests/incremental_tb.py +++ b/test/tests/incremental_tb.py @@ -52,3 +52,18 @@ def f3(): print et1 is et2 print ev1 is ev2 print tb1 is tb2 + +class C(object): + def __getattr__(self, attr): + raise AttributeError() + +def f4(): + try: + C().a + except IOError: # unrelated exception + pass + +try: + f4() +except AttributeError: + print "******** 3", ''.join(traceback.format_exception(*sys.exc_info())) diff --git a/test/tests/incremental_tb_bjit.py b/test/tests/incremental_tb_bjit.py index c2d16a5d1..028044ff9 100644 --- a/test/tests/incremental_tb_bjit.py +++ b/test/tests/incremental_tb_bjit.py @@ -4,57 +4,5 @@ __pyston__.setOption("REOPT_THRESHOLD_INTERPRETER", 1) except: pass -import traceback -import sys -def f(): - a, b, c = sys.exc_info() - raise a, b, c -et0, ev0, tb0 = None, None, None - -try: - 1/0 -except: - pass - -for i in xrange(10): - try: - f() - except: - et0, ev0, tb0 = sys.exc_info() - -print "******** 0", ''.join(traceback.format_exception(et0, ev0, tb0)) - - -et1, ev1, tb1 = None, None, None -et2, ev2, tb2 = None, None, None - -def f1(): - raise - -def f2(): - f1() - -def f21(): - raise Exception() - -def f3(): - try: - f21() - except: - global et1, tv1, tb1 - et1, tv1, tb1 = sys.exc_info() - f2() - - -try: - f3() -except: - et2, tv2, tb2 = sys.exc_info() - -print "******** 1", ''.join(traceback.format_exception(et1, ev1, tb1)) -print "******** 2", ''.join(traceback.format_exception(et2, ev2, tb2)) - -print et1 is et2 -print ev1 is ev2 -print tb1 is tb2 +import incremental_tb