Commit b82d1414 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #790 from kmod/exceptions2

Make Raise and Subscript exprs use capi exceptions
parents 3f883401 0514bf3c
...@@ -337,6 +337,10 @@ public: ...@@ -337,6 +337,10 @@ public:
CompilerVariable* slice) override { CompilerVariable* slice) override {
ConcreteCompilerVariable* converted_slice = slice->makeConverted(emitter, slice->getBoxType()); ConcreteCompilerVariable* converted_slice = slice->makeConverted(emitter, slice->getBoxType());
ExceptionStyle target_exception_style = CXX;
if (FORCE_LLVM_CAPI || info.unw_info.capi_exc_dest)
target_exception_style = CAPI;
bool do_patchpoint = ENABLE_ICGETITEMS; bool do_patchpoint = ENABLE_ICGETITEMS;
llvm::Value* rtn; llvm::Value* rtn;
if (do_patchpoint) { if (do_patchpoint) {
...@@ -346,13 +350,20 @@ public: ...@@ -346,13 +350,20 @@ public:
llvm_args.push_back(var->getValue()); llvm_args.push_back(var->getValue());
llvm_args.push_back(converted_slice->getValue()); llvm_args.push_back(converted_slice->getValue());
llvm::Value* uncasted = emitter.createIC(pp, (void*)pyston::getitem, llvm_args, info.unw_info); llvm::Value* uncasted
= emitter.createIC(pp, (void*)(target_exception_style == CAPI ? pyston::getitem_capi : pyston::getitem),
llvm_args, info.unw_info, target_exception_style);
rtn = emitter.getBuilder()->CreateIntToPtr(uncasted, g.llvm_value_type_ptr); rtn = emitter.getBuilder()->CreateIntToPtr(uncasted, g.llvm_value_type_ptr);
} else { } else {
rtn = emitter.createCall2(info.unw_info, g.funcs.getitem, var->getValue(), converted_slice->getValue()); rtn = emitter.createCall2(info.unw_info,
target_exception_style == CAPI ? g.funcs.getitem_capi : g.funcs.getitem,
var->getValue(), converted_slice->getValue(), target_exception_style);
} }
converted_slice->decvref(emitter); converted_slice->decvref(emitter);
if (target_exception_style == CAPI)
emitter.checkAndPropagateCapiException(info.unw_info, rtn, getNullPtr(g.llvm_value_type_ptr));
return new ConcreteCompilerVariable(UNKNOWN, rtn, true); return new ConcreteCompilerVariable(UNKNOWN, rtn, true);
} }
...@@ -490,7 +501,7 @@ CompilerVariable* UnknownType::getattr(IREmitter& emitter, const OpInfo& info, C ...@@ -490,7 +501,7 @@ CompilerVariable* UnknownType::getattr(IREmitter& emitter, const OpInfo& info, C
llvm::Value* rtn_val = NULL; llvm::Value* rtn_val = NULL;
ExceptionStyle target_exception_style = CXX; ExceptionStyle target_exception_style = CXX;
if (info.unw_info.capi_exc_dest) if (info.unw_info.capi_exc_dest || (!cls_only && FORCE_LLVM_CAPI))
target_exception_style = CAPI; target_exception_style = CAPI;
llvm::Value* llvm_func; llvm::Value* llvm_func;
...@@ -1494,7 +1505,7 @@ public: ...@@ -1494,7 +1505,7 @@ public:
if (canStaticallyResolveGetattrs()) { if (canStaticallyResolveGetattrs()) {
Box* rtattr = typeLookup(cls, attr, nullptr); Box* rtattr = typeLookup(cls, attr, nullptr);
if (rtattr == NULL) { if (rtattr == NULL) {
ExceptionStyle exception_style = info.unw_info.capi_exc_dest ? CAPI : CXX; ExceptionStyle exception_style = (FORCE_LLVM_CAPI || info.unw_info.capi_exc_dest) ? CAPI : CXX;
llvm::Value* raise_func = exception_style == CXX ? g.funcs.raiseAttributeErrorStr llvm::Value* raise_func = exception_style == CXX ? g.funcs.raiseAttributeErrorStr
: g.funcs.raiseAttributeErrorStrCapi; : g.funcs.raiseAttributeErrorStrCapi;
llvm::CallSite call = emitter.createCall3( llvm::CallSite call = emitter.createCall3(
...@@ -1546,7 +1557,7 @@ public: ...@@ -1546,7 +1557,7 @@ public:
BoxedString* attr, bool clsonly, ArgPassSpec argspec, BoxedString* attr, bool clsonly, ArgPassSpec argspec,
const std::vector<CompilerVariable*>& args, const std::vector<CompilerVariable*>& args,
const std::vector<BoxedString*>* keyword_names, const std::vector<BoxedString*>* keyword_names,
bool* no_attribute = NULL) { bool* no_attribute = NULL, ExceptionStyle exception_style = CXX) {
if (!canStaticallyResolveGetattrs()) if (!canStaticallyResolveGetattrs())
return NULL; return NULL;
...@@ -1555,10 +1566,18 @@ public: ...@@ -1555,10 +1566,18 @@ public:
if (no_attribute) { if (no_attribute) {
*no_attribute = true; *no_attribute = true;
} else { } else {
llvm::Value* raise_func = exception_style == CXX ? g.funcs.raiseAttributeErrorStr
: g.funcs.raiseAttributeErrorStrCapi;
llvm::CallSite call = emitter.createCall3( llvm::CallSite call = emitter.createCall3(
info.unw_info, g.funcs.raiseAttributeErrorStr, embedRelocatablePtr(cls->tp_name, g.i8_ptr), info.unw_info, raise_func, embedRelocatablePtr(cls->tp_name, g.i8_ptr),
embedRelocatablePtr(attr->data(), g.i8_ptr), getConstantInt(attr->size(), g.i64)); embedRelocatablePtr(attr->data(), g.i8_ptr), getConstantInt(attr->size(), g.i64), exception_style);
call.setDoesNotReturn(); 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(); return undefVariable();
} }
...@@ -1589,6 +1608,9 @@ public: ...@@ -1589,6 +1608,9 @@ public:
cf = cl->versions[i]; cf = cl->versions[i];
assert(cf->spec->arg_types.size() == cl->numReceivedArgs()); assert(cf->spec->arg_types.size() == cl->numReceivedArgs());
if (cf->exception_style != exception_style)
continue;
bool fits = true; bool fits = true;
for (int j = 0; j < args.size(); j++) { for (int j = 0; j < args.size(); j++) {
if (!args[j]->canConvertTo(cf->spec->arg_types[j + 1])) { if (!args[j]->canConvertTo(cf->spec->arg_types[j + 1])) {
...@@ -1603,8 +1625,12 @@ public: ...@@ -1603,8 +1625,12 @@ public:
break; break;
} }
assert(found); if (!found && exception_style == CAPI) {
assert(cf->code); std::string name = g.func_addr_registry.getFuncNameAtAddress(cl->versions[0]->code, true);
RELEASE_ASSERT(0, "Please define a capi variant for %s", name.c_str());
}
RELEASE_ASSERT(found, "");
RELEASE_ASSERT(cf->code, "");
std::vector<llvm::Type*> arg_types; std::vector<llvm::Type*> arg_types;
RELEASE_ASSERT(paramspec.num_args == cl->numReceivedArgs(), ""); RELEASE_ASSERT(paramspec.num_args == cl->numReceivedArgs(), "");
...@@ -1733,8 +1759,13 @@ public: ...@@ -1733,8 +1759,13 @@ public:
CompilerVariable* getitem(IREmitter& emitter, const OpInfo& info, VAR* var, CompilerVariable* slice) override { CompilerVariable* getitem(IREmitter& emitter, const OpInfo& info, VAR* var, CompilerVariable* slice) override {
static BoxedString* attr = internStringImmortal("__getitem__"); static BoxedString* attr = internStringImmortal("__getitem__");
bool no_attribute = false; bool no_attribute = false;
ExceptionStyle exception_style = CXX;
if (FORCE_LLVM_CAPI || info.unw_info.capi_exc_dest)
exception_style = CAPI;
ConcreteCompilerVariable* called_constant = tryCallattrConstant( ConcreteCompilerVariable* called_constant = tryCallattrConstant(
emitter, info, var, attr, true, ArgPassSpec(1, 0, 0, 0), { slice }, NULL, &no_attribute); emitter, info, var, attr, true, ArgPassSpec(1, 0, 0, 0), { slice }, NULL, &no_attribute, exception_style);
if (no_attribute) { if (no_attribute) {
assert(called_constant->getType() == UNDEF); assert(called_constant->getType() == UNDEF);
...@@ -2239,9 +2270,20 @@ public: ...@@ -2239,9 +2270,20 @@ public:
rtn->incvref(); rtn->incvref();
return rtn; return rtn;
} else { } else {
llvm::CallSite call = emitter.createCall(info.unw_info, g.funcs.raiseIndexErrorStr, ExceptionStyle target_exception_style = CXX;
embedConstantPtr("tuple", g.i8_ptr)); if (FORCE_LLVM_CAPI || info.unw_info.capi_exc_dest)
call.setDoesNotReturn(); target_exception_style = CAPI;
if (target_exception_style == CAPI) {
llvm::CallSite call = emitter.createCall(info.unw_info, g.funcs.raiseIndexErrorStrCapi,
embedConstantPtr("tuple", g.i8_ptr), CAPI);
emitter.checkAndPropagateCapiException(info.unw_info, getNullPtr(g.llvm_value_type_ptr),
getNullPtr(g.llvm_value_type_ptr));
} else {
llvm::CallSite call = emitter.createCall(info.unw_info, g.funcs.raiseIndexErrorStr,
embedConstantPtr("tuple", g.i8_ptr), CXX);
call.setDoesNotReturn();
}
return undefVariable(); return undefVariable();
} }
} }
......
...@@ -40,6 +40,8 @@ void compileAndRunModule(AST_Module* m, BoxedModule* bm); ...@@ -40,6 +40,8 @@ void compileAndRunModule(AST_Module* m, BoxedModule* bm);
CompiledFunction* cfForMachineFunctionName(const std::string&); CompiledFunction* cfForMachineFunctionName(const std::string&);
extern "C" void capiExcCaughtInJit(AST_stmt* current_stmt, void* source_info); extern "C" void capiExcCaughtInJit(AST_stmt* current_stmt, void* source_info);
// This is just meant for the use of the JIT (normal runtime code should call throwCAPIException)
extern "C" void reraiseJitCapiExc() __attribute__((noreturn));
extern "C" Box* exec(Box* boxedCode, Box* globals, Box* locals, FutureFlags caller_future_flags); 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* eval(Box* boxedCode, Box* globals, Box* locals);
......
...@@ -107,8 +107,15 @@ ExceptionStyle IRGenState::getLandingpadStyle(AST_Invoke* invoke) { ...@@ -107,8 +107,15 @@ ExceptionStyle IRGenState::getLandingpadStyle(AST_Invoke* invoke) {
r = CXX; // default r = CXX; // default
// print_ast(invoke); if (invoke->stmt->type == AST_TYPE::Raise) {
// printf("\n"); AST_Raise* raise_stmt = ast_cast<AST_Raise>(invoke->stmt);
// Currently can't do a re-raise with a capi exception:
if (raise_stmt->arg0 && !raise_stmt->arg2) {
r = CAPI;
return r;
}
}
AST_expr* expr = NULL; AST_expr* expr = NULL;
if (invoke->stmt->type == AST_TYPE::Assign) { if (invoke->stmt->type == AST_TYPE::Assign) {
...@@ -129,7 +136,7 @@ ExceptionStyle IRGenState::getLandingpadStyle(AST_Invoke* invoke) { ...@@ -129,7 +136,7 @@ ExceptionStyle IRGenState::getLandingpadStyle(AST_Invoke* invoke) {
return r; return r;
} }
if (expr->type == AST_TYPE::Attribute) { if (expr->type == AST_TYPE::Attribute || expr->type == AST_TYPE::Subscript) {
r = CAPI; r = CAPI;
// printf("Doing a capi exception to %d\n", invoke->exc_dest->idx); // printf("Doing a capi exception to %d\n", invoke->exc_dest->idx);
return r; return r;
...@@ -298,42 +305,6 @@ private: ...@@ -298,42 +305,6 @@ private:
} }
} }
void checkAndPropagateCapiException(const UnwindInfo& unw_info, llvm::Value* returned_val, llvm::Value* exc_val,
bool double_check) override {
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, llvm::CallSite emitPatchpoint(llvm::Type* return_type, const ICSetupInfo* pp, llvm::Value* func,
const std::vector<llvm::Value*>& args, const std::vector<llvm::Value*>& args,
const std::vector<llvm::Value*>& ic_stackmap_args, const UnwindInfo& unw_info, const std::vector<llvm::Value*>& ic_stackmap_args, const UnwindInfo& unw_info,
...@@ -507,6 +478,43 @@ public: ...@@ -507,6 +478,43 @@ public:
return rtn.getInstruction(); return rtn.getInstruction();
} }
void checkAndPropagateCapiException(const UnwindInfo& unw_info, llvm::Value* returned_val, llvm::Value* exc_val,
bool double_check = false) override {
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) {
getBuilder()->CreateCall(g.funcs.reraiseJitCapiExc);
getBuilder()->CreateUnreachable();
}
setCurrentBasicBlock(normal_dest);
}
Box* getIntConstant(int64_t n) override { return irstate->getSourceInfo()->parent_module->getIntConstant(n); } Box* getIntConstant(int64_t n) override { return irstate->getSourceInfo()->parent_module->getIntConstant(n); }
Box* getFloatConstant(double d) override { return irstate->getSourceInfo()->parent_module->getFloatConstant(d); } Box* getFloatConstant(double d) override { return irstate->getSourceInfo()->parent_module->getFloatConstant(d); }
...@@ -2310,10 +2318,15 @@ private: ...@@ -2310,10 +2318,15 @@ private:
// It looks like ommitting the second and third arguments are equivalent to passing None, // 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. // but ommitting the first argument is *not* the same as passing None.
ExceptionStyle target_exception_style = CXX;
if (unw_info.capi_exc_dest || (FORCE_LLVM_CAPI && node->arg0 && !node->arg2))
target_exception_style = CAPI;
if (node->arg0 == NULL) { if (node->arg0 == NULL) {
assert(!node->arg1); assert(!node->arg1);
assert(!node->arg2); assert(!node->arg2);
assert(target_exception_style == CXX);
emitter.createCall(unw_info, g.funcs.raise0, std::vector<llvm::Value*>()); emitter.createCall(unw_info, g.funcs.raise0, std::vector<llvm::Value*>());
emitter.getBuilder()->CreateUnreachable(); emitter.getBuilder()->CreateUnreachable();
...@@ -2333,7 +2346,13 @@ private: ...@@ -2333,7 +2346,13 @@ private:
} }
} }
emitter.createCall(unw_info, g.funcs.raise3, args); if (target_exception_style == CAPI) {
emitter.createCall(unw_info, g.funcs.raise3_capi, args, CAPI);
emitter.checkAndPropagateCapiException(unw_info, getNullPtr(g.llvm_value_type_ptr),
getNullPtr(g.llvm_value_type_ptr));
} else {
emitter.createCall(unw_info, g.funcs.raise3, args, CXX);
}
emitter.getBuilder()->CreateUnreachable(); emitter.getBuilder()->CreateUnreachable();
endBlock(DEAD); endBlock(DEAD);
......
...@@ -199,6 +199,7 @@ void initGlobalFuncs(GlobalState& g) { ...@@ -199,6 +199,7 @@ void initGlobalFuncs(GlobalState& g) {
GET(setattr); GET(setattr);
GET(delattr); GET(delattr);
GET(getitem); GET(getitem);
GET(getitem_capi);
GET(setitem); GET(setitem);
GET(delitem); GET(delitem);
GET(getGlobal); GET(getGlobal);
...@@ -227,6 +228,7 @@ void initGlobalFuncs(GlobalState& g) { ...@@ -227,6 +228,7 @@ void initGlobalFuncs(GlobalState& g) {
GET(raiseAttributeErrorCapi); GET(raiseAttributeErrorCapi);
GET(raiseAttributeErrorStrCapi); GET(raiseAttributeErrorStrCapi);
GET(raiseIndexErrorStr); GET(raiseIndexErrorStr);
GET(raiseIndexErrorStrCapi);
GET(raiseNotIterableError); GET(raiseNotIterableError);
GET(assertNameDefined); GET(assertNameDefined);
GET(assertFailDerefNameDefined); GET(assertFailDerefNameDefined);
...@@ -273,9 +275,11 @@ void initGlobalFuncs(GlobalState& g) { ...@@ -273,9 +275,11 @@ void initGlobalFuncs(GlobalState& g) {
g.funcs.__cxa_end_catch = addFunc((void*)__cxa_end_catch, g.void_); g.funcs.__cxa_end_catch = addFunc((void*)__cxa_end_catch, g.void_);
GET(raise0); GET(raise0);
GET(raise3); GET(raise3);
GET(raise3_capi);
GET(PyErr_Fetch); GET(PyErr_Fetch);
GET(PyErr_NormalizeException); GET(PyErr_NormalizeException);
GET(capiExcCaughtInJit); GET(capiExcCaughtInJit);
GET(reraiseJitCapiExc);
GET(deopt); GET(deopt);
GET(div_float_float); GET(div_float_float);
......
...@@ -36,12 +36,12 @@ struct GlobalFuncs { ...@@ -36,12 +36,12 @@ struct GlobalFuncs {
*boxBool, *unboxBool, *createTuple, *createDict, *createList, *createSlice, *createUserClass, *createClosure, *boxBool, *unboxBool, *createTuple, *createDict, *createList, *createSlice, *createUserClass, *createClosure,
*createGenerator, *createSet; *createGenerator, *createSet;
llvm::Value* getattr, *getattr_capi, *setattr, *delattr, *delitem, *delGlobal, *nonzero, *binop, *compare, llvm::Value* getattr, *getattr_capi, *setattr, *delattr, *delitem, *delGlobal, *nonzero, *binop, *compare,
*augbinop, *unboxedLen, *getitem, *getclsattr, *getGlobal, *setitem, *unaryop, *import, *importFrom, *augbinop, *unboxedLen, *getitem, *getitem_capi, *getclsattr, *getGlobal, *setitem, *unaryop, *import,
*importStar, *repr, *str, *strOrUnicode, *exceptionMatches, *yield, *getiterHelper, *hasnext; *importFrom, *importStar, *repr, *str, *strOrUnicode, *exceptionMatches, *yield, *getiterHelper, *hasnext;
llvm::Value* unpackIntoArray, *raiseAttributeError, *raiseAttributeErrorStr, *raiseAttributeErrorCapi, llvm::Value* unpackIntoArray, *raiseAttributeError, *raiseAttributeErrorStr, *raiseAttributeErrorCapi,
*raiseAttributeErrorStrCapi, *raiseNotIterableError, *raiseIndexErrorStr, *assertNameDefined, *assertFail, *raiseAttributeErrorStrCapi, *raiseNotIterableError, *raiseIndexErrorStr, *raiseIndexErrorStrCapi,
*assertFailDerefNameDefined; *assertNameDefined, *assertFail, *assertFailDerefNameDefined;
llvm::Value* printFloat, *listAppendInternal, *getSysStdout; llvm::Value* printFloat, *listAppendInternal, *getSysStdout;
llvm::Value* runtimeCall0, *runtimeCall1, *runtimeCall2, *runtimeCall3, *runtimeCall, *runtimeCallN; llvm::Value* runtimeCall0, *runtimeCall1, *runtimeCall2, *runtimeCall3, *runtimeCall, *runtimeCallN;
llvm::Value* callattr0, *callattr1, *callattr2, *callattr3, *callattr, *callattrN; llvm::Value* callattr0, *callattr1, *callattr2, *callattr3, *callattr, *callattrN;
...@@ -50,8 +50,8 @@ struct GlobalFuncs { ...@@ -50,8 +50,8 @@ 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, *raise3; llvm::Value* raise0, *raise3, *raise3_capi;
llvm::Value* PyErr_Fetch, *PyErr_NormalizeException, *capiExcCaughtInJit; llvm::Value* PyErr_Fetch, *PyErr_NormalizeException, *capiExcCaughtInJit, *reraiseJitCapiExc;
llvm::Value* deopt; llvm::Value* deopt;
llvm::Value* div_float_float, *floordiv_float_float, *mod_float_float, *pow_float_float; llvm::Value* div_float_float, *floordiv_float_float, *mod_float_float, *pow_float_float;
......
...@@ -481,6 +481,16 @@ bool frameIsPythonFrame(unw_word_t ip, unw_word_t bp, unw_cursor_t* cursor, Pyth ...@@ -481,6 +481,16 @@ bool frameIsPythonFrame(unw_word_t ip, unw_word_t bp, unw_cursor_t* cursor, Pyth
return true; return true;
} }
static const LineInfo lineInfoForFrame(PythonFrameIteratorImpl* frame_it) {
AST_stmt* current_stmt = frame_it->getCurrentStatement();
auto* cl = frame_it->getCL();
assert(cl);
auto source = cl->source.get();
return LineInfo(current_stmt->lineno, current_stmt->col_offset, source->fn, source->getName());
}
class PythonUnwindSession : public Box { class PythonUnwindSession : public Box {
ExcInfo exc_info; ExcInfo exc_info;
bool skip; bool skip;
...@@ -518,12 +528,13 @@ public: ...@@ -518,12 +528,13 @@ public:
stat.log(t.end()); stat.log(t.end());
} }
void addTraceback(const LineInfo& line_info) { void addTraceback(PythonFrameIteratorImpl& frame_iter) {
RELEASE_ASSERT(is_active, ""); RELEASE_ASSERT(is_active, "");
if (exc_info.reraise) { if (exc_info.reraise) {
exc_info.reraise = false; exc_info.reraise = false;
return; return;
} }
auto line_info = lineInfoForFrame(&frame_iter);
BoxedTraceback::here(line_info, &exc_info.traceback); BoxedTraceback::here(line_info, &exc_info.traceback);
} }
...@@ -593,16 +604,6 @@ void throwingException(PythonUnwindSession* unwind) { ...@@ -593,16 +604,6 @@ void throwingException(PythonUnwindSession* unwind) {
unwind->logException(); unwind->logException();
} }
static const LineInfo lineInfoForFrame(PythonFrameIteratorImpl* frame_it) {
AST_stmt* current_stmt = frame_it->getCurrentStatement();
auto* cl = frame_it->getCL();
assert(cl);
auto source = cl->source.get();
return LineInfo(current_stmt->lineno, current_stmt->col_offset, source->fn, source->getName());
}
extern "C" void capiExcCaughtInJit(AST_stmt* stmt, void* _source_info) { extern "C" void capiExcCaughtInJit(AST_stmt* stmt, void* _source_info) {
SourceInfo* source = static_cast<SourceInfo*>(_source_info); SourceInfo* source = static_cast<SourceInfo*>(_source_info);
// TODO: handle reraise (currently on the ExcInfo object) // TODO: handle reraise (currently on the ExcInfo object)
...@@ -611,6 +612,16 @@ extern "C" void capiExcCaughtInJit(AST_stmt* stmt, void* _source_info) { ...@@ -611,6 +612,16 @@ extern "C" void capiExcCaughtInJit(AST_stmt* stmt, void* _source_info) {
&tstate->curexc_traceback); &tstate->curexc_traceback);
} }
extern "C" void reraiseJitCapiExc() {
ensureCAPIExceptionSet();
// TODO: we are normalizing to many times?
ExcInfo e = excInfoForRaise(cur_thread_state.curexc_type, cur_thread_state.curexc_value,
cur_thread_state.curexc_traceback);
PyErr_Clear();
e.reraise = true;
throw e;
}
void exceptionCaughtInInterpreter(LineInfo line_info, ExcInfo* exc_info) { void exceptionCaughtInInterpreter(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();
...@@ -647,7 +658,7 @@ void unwindingThroughFrame(PythonUnwindSession* unwind_session, unw_cursor_t* cu ...@@ -647,7 +658,7 @@ void unwindingThroughFrame(PythonUnwindSession* unwind_session, unw_cursor_t* cu
frames_unwound.log(); frames_unwound.log();
if (!unwind_session->shouldSkipFrame()) if (!unwind_session->shouldSkipFrame())
unwind_session->addTraceback(lineInfoForFrame(&frame_iter)); unwind_session->addTraceback(frame_iter);
// frame_iter->cf->entry_descriptor will be non-null for OSR frames. // frame_iter->cf->entry_descriptor will be non-null for OSR frames.
bool was_osr = (frame_iter.getId().type == PythonFrameId::COMPILED) && (frame_iter.cf->entry_descriptor); bool was_osr = (frame_iter.getId().type == PythonFrameId::COMPILED) && (frame_iter.cf->entry_descriptor);
......
...@@ -44,6 +44,9 @@ bool ENABLE_PYPA_PARSER = true; ...@@ -44,6 +44,9 @@ bool ENABLE_PYPA_PARSER = true;
bool USE_REGALLOC_BASIC = true; bool USE_REGALLOC_BASIC = true;
bool PAUSE_AT_ABORT = false; bool PAUSE_AT_ABORT = false;
bool ENABLE_TRACEBACKS = true; bool ENABLE_TRACEBACKS = true;
// Forces the llvm jit to use capi exceptions whenever it can, as opposed to whenever it thinks
// it is faster:
bool FORCE_LLVM_CAPI = false;
int OSR_THRESHOLD_INTERPRETER = 25; int OSR_THRESHOLD_INTERPRETER = 25;
int REOPT_THRESHOLD_INTERPRETER = 25; int REOPT_THRESHOLD_INTERPRETER = 25;
......
...@@ -39,7 +39,7 @@ extern int MAX_OBJECT_CACHE_ENTRIES; ...@@ -39,7 +39,7 @@ extern int MAX_OBJECT_CACHE_ENTRIES;
extern bool SHOW_DISASM, FORCE_INTERPRETER, FORCE_OPTIMIZE, PROFILE, DUMPJIT, TRAP, USE_STRIPPED_STDLIB, extern bool SHOW_DISASM, FORCE_INTERPRETER, FORCE_OPTIMIZE, PROFILE, DUMPJIT, TRAP, USE_STRIPPED_STDLIB,
CONTINUE_AFTER_FATAL, ENABLE_INTERPRETER, ENABLE_BASELINEJIT, ENABLE_PYPA_PARSER, USE_REGALLOC_BASIC, CONTINUE_AFTER_FATAL, ENABLE_INTERPRETER, ENABLE_BASELINEJIT, ENABLE_PYPA_PARSER, USE_REGALLOC_BASIC,
PAUSE_AT_ABORT, ENABLE_TRACEBACKS, ASSEMBLY_LOGGING; PAUSE_AT_ABORT, ENABLE_TRACEBACKS, ASSEMBLY_LOGGING, FORCE_LLVM_CAPI;
extern bool ENABLE_ICS, ENABLE_ICGENERICS, ENABLE_ICGETITEMS, ENABLE_ICSETITEMS, ENABLE_ICDELITEMS, ENABLE_ICBINEXPS, extern bool ENABLE_ICS, ENABLE_ICGENERICS, ENABLE_ICGETITEMS, ENABLE_ICSETITEMS, ENABLE_ICDELITEMS, ENABLE_ICBINEXPS,
ENABLE_ICNONZEROS, ENABLE_ICCALLSITES, ENABLE_ICSETATTRS, ENABLE_ICGETATTRS, ENALBE_ICDELATTRS, ENABLE_ICGETGLOBALS, ENABLE_ICNONZEROS, ENABLE_ICCALLSITES, ENABLE_ICSETATTRS, ENABLE_ICGETATTRS, ENALBE_ICDELATTRS, ENABLE_ICGETGLOBALS,
......
...@@ -242,6 +242,7 @@ struct ParamReceiveSpec { ...@@ -242,6 +242,7 @@ struct ParamReceiveSpec {
bool operator!=(ParamReceiveSpec rhs) { return !(*this == rhs); } bool operator!=(ParamReceiveSpec rhs) { return !(*this == rhs); }
int totalReceived() { return num_args + (takes_varargs ? 1 : 0) + (takes_kwargs ? 1 : 0); } int totalReceived() { return num_args + (takes_varargs ? 1 : 0) + (takes_kwargs ? 1 : 0); }
int kwargsIndex() { return num_args + (takes_varargs ? 1 : 0); }
}; };
class ICInvalidator { class ICInvalidator {
......
...@@ -227,7 +227,7 @@ template <enum ExceptionStyle S> Box* dictGetitem(BoxedDict* self, Box* k) noexc ...@@ -227,7 +227,7 @@ template <enum ExceptionStyle S> Box* dictGetitem(BoxedDict* self, Box* k) noexc
} }
if (S == CAPI) { if (S == CAPI) {
PyErr_SetObject(KeyError, k); PyErr_SetObject(KeyError, BoxedTuple::create1(k));
return NULL; return NULL;
} else } else
raiseExcHelper(KeyError, k); raiseExcHelper(KeyError, k);
...@@ -746,7 +746,9 @@ void setupDict() { ...@@ -746,7 +746,9 @@ void setupDict() {
dict_cls->giveAttr("setdefault", dict_cls->giveAttr("setdefault",
new BoxedFunction(boxRTFunction((void*)dictSetdefault, UNKNOWN, 3, 1, false, false), { None })); new BoxedFunction(boxRTFunction((void*)dictSetdefault, UNKNOWN, 3, 1, false, false), { None }));
dict_cls->giveAttr("__getitem__", new BoxedFunction(boxRTFunction((void*)dictGetitem<CXX>, UNKNOWN, 2))); auto dict_getitem = boxRTFunction((void*)dictGetitem<CXX>, UNKNOWN, 2, ParamNames::empty(), CXX);
addRTFunction(dict_getitem, (void*)dictGetitem<CAPI>, UNKNOWN, CAPI);
dict_cls->giveAttr("__getitem__", new BoxedFunction(dict_getitem));
dict_cls->giveAttr("__setitem__", new BoxedFunction(boxRTFunction((void*)dictSetitem, NONE, 3))); dict_cls->giveAttr("__setitem__", new BoxedFunction(boxRTFunction((void*)dictSetitem, NONE, 3)));
dict_cls->giveAttr("__delitem__", new BoxedFunction(boxRTFunction((void*)dictDelitem, UNKNOWN, 2))); dict_cls->giveAttr("__delitem__", new BoxedFunction(boxRTFunction((void*)dictDelitem, UNKNOWN, 2)));
dict_cls->giveAttr("__contains__", new BoxedFunction(boxRTFunction((void*)dictContains, BOXED_BOOL, 2))); dict_cls->giveAttr("__contains__", new BoxedFunction(boxRTFunction((void*)dictContains, BOXED_BOOL, 2)));
......
...@@ -83,6 +83,7 @@ void force() { ...@@ -83,6 +83,7 @@ void force() {
FORCE(augbinop); FORCE(augbinop);
FORCE(unboxedLen); FORCE(unboxedLen);
FORCE(getitem); FORCE(getitem);
FORCE(getitem_capi);
FORCE(getclsattr); FORCE(getclsattr);
FORCE(getGlobal); FORCE(getGlobal);
FORCE(delGlobal); FORCE(delGlobal);
...@@ -105,6 +106,7 @@ void force() { ...@@ -105,6 +106,7 @@ void force() {
FORCE(raiseAttributeErrorCapi); FORCE(raiseAttributeErrorCapi);
FORCE(raiseAttributeErrorStrCapi); FORCE(raiseAttributeErrorStrCapi);
FORCE(raiseIndexErrorStr); FORCE(raiseIndexErrorStr);
FORCE(raiseIndexErrorStrCapi);
FORCE(raiseNotIterableError); FORCE(raiseNotIterableError);
FORCE(assertNameDefined); FORCE(assertNameDefined);
FORCE(assertFailDerefNameDefined); FORCE(assertFailDerefNameDefined);
...@@ -120,9 +122,11 @@ void force() { ...@@ -120,9 +122,11 @@ void force() {
FORCE(raise0); FORCE(raise0);
FORCE(raise3); FORCE(raise3);
FORCE(raise3_capi);
FORCE(PyErr_Fetch); FORCE(PyErr_Fetch);
FORCE(PyErr_NormalizeException); FORCE(PyErr_NormalizeException);
FORCE(capiExcCaughtInJit); FORCE(capiExcCaughtInJit);
FORCE(reraiseJitCapiExc);
FORCE(deopt); FORCE(deopt);
FORCE(div_i64_i64); FORCE(div_i64_i64);
......
...@@ -224,7 +224,16 @@ extern "C" PyObject* PyList_GetItem(PyObject* op, Py_ssize_t i) noexcept { ...@@ -224,7 +224,16 @@ extern "C" PyObject* PyList_GetItem(PyObject* op, Py_ssize_t i) noexcept {
} }
} }
extern "C" Box* listGetitemSlice(BoxedList* self, BoxedSlice* slice) { template <ExceptionStyle S> Box* listGetitemSlice(BoxedList* self, BoxedSlice* slice) {
if (S == CAPI) {
try {
return listGetitemSlice<CXX>(self, slice);
} catch (ExcInfo e) {
setCAPIException(e);
return NULL;
}
}
assert(isSubclass(self->cls, list_cls)); assert(isSubclass(self->cls, list_cls));
assert(slice->cls == slice_cls); assert(slice->cls == slice_cls);
i64 start, stop, step, length; i64 start, stop, step, length;
...@@ -242,7 +251,16 @@ extern "C" Box* listGetslice(BoxedList* self, Box* boxedStart, Box* boxedStop) { ...@@ -242,7 +251,16 @@ extern "C" Box* listGetslice(BoxedList* self, Box* boxedStart, Box* boxedStop) {
return _listSlice(self, start, stop, 1, stop - start); return _listSlice(self, start, stop, 1, stop - start);
} }
extern "C" Box* listGetitem(BoxedList* self, Box* slice) { template <ExceptionStyle S> Box* listGetitem(BoxedList* self, Box* slice) {
if (S == CAPI) {
try {
return listGetitem<CXX>(self, slice);
} catch (ExcInfo e) {
setCAPIException(e);
return NULL;
}
}
assert(isSubclass(self->cls, list_cls)); assert(isSubclass(self->cls, list_cls));
if (PyIndex_Check(slice)) { if (PyIndex_Check(slice)) {
Py_ssize_t i = PyNumber_AsSsize_t(slice, PyExc_IndexError); Py_ssize_t i = PyNumber_AsSsize_t(slice, PyExc_IndexError);
...@@ -250,7 +268,7 @@ extern "C" Box* listGetitem(BoxedList* self, Box* slice) { ...@@ -250,7 +268,7 @@ extern "C" Box* listGetitem(BoxedList* self, Box* slice) {
throwCAPIException(); throwCAPIException();
return listGetitemUnboxed(self, i); return listGetitemUnboxed(self, i);
} else if (slice->cls == slice_cls) { } else if (slice->cls == slice_cls) {
return listGetitemSlice(self, static_cast<BoxedSlice*>(slice)); return listGetitemSlice<CXX>(self, static_cast<BoxedSlice*>(slice));
} else { } else {
raiseExcHelper(TypeError, "list indices must be integers, not %s", getTypeName(slice)); raiseExcHelper(TypeError, "list indices must be integers, not %s", getTypeName(slice));
} }
...@@ -799,13 +817,8 @@ extern "C" int PyList_Sort(PyObject* v) noexcept { ...@@ -799,13 +817,8 @@ extern "C" int PyList_Sort(PyObject* v) noexcept {
extern "C" Box* PyList_GetSlice(PyObject* a, Py_ssize_t ilow, Py_ssize_t ihigh) noexcept { extern "C" Box* PyList_GetSlice(PyObject* a, Py_ssize_t ilow, Py_ssize_t ihigh) noexcept {
assert(isSubclass(a->cls, list_cls)); assert(isSubclass(a->cls, list_cls));
BoxedList* self = static_cast<BoxedList*>(a); BoxedList* self = static_cast<BoxedList*>(a);
try { // Lots of extra copies here; we can do better if we need to:
// Lots of extra copies here; we can do better if we need to: return listGetitemSlice<CAPI>(self, new BoxedSlice(boxInt(ilow), boxInt(ihigh), boxInt(1)));
return listGetitemSlice(self, new BoxedSlice(boxInt(ilow), boxInt(ihigh), boxInt(1)));
} catch (ExcInfo e) {
setCAPIException(e);
return NULL;
}
} }
Box* listContains(BoxedList* self, Box* elt) { Box* listContains(BoxedList* self, Box* elt) {
...@@ -1092,8 +1105,13 @@ void setupList() { ...@@ -1092,8 +1105,13 @@ void setupList() {
CLFunction* getitem = createRTFunction(2, 0, false, false); CLFunction* getitem = createRTFunction(2, 0, false, false);
addRTFunction(getitem, (void*)listGetitemInt, UNKNOWN, std::vector<ConcreteCompilerType*>{ LIST, BOXED_INT }); addRTFunction(getitem, (void*)listGetitemInt, UNKNOWN, std::vector<ConcreteCompilerType*>{ LIST, BOXED_INT });
addRTFunction(getitem, (void*)listGetitemSlice, LIST, std::vector<ConcreteCompilerType*>{ LIST, SLICE }); addRTFunction(getitem, (void*)listGetitemSlice<CXX>, LIST, std::vector<ConcreteCompilerType*>{ LIST, SLICE }, CXX);
addRTFunction(getitem, (void*)listGetitem, UNKNOWN, std::vector<ConcreteCompilerType*>{ UNKNOWN, UNKNOWN }); addRTFunction(getitem, (void*)listGetitem<CXX>, UNKNOWN, std::vector<ConcreteCompilerType*>{ UNKNOWN, UNKNOWN },
CXX);
addRTFunction(getitem, (void*)listGetitemSlice<CAPI>, LIST, std::vector<ConcreteCompilerType*>{ LIST, SLICE },
CAPI);
addRTFunction(getitem, (void*)listGetitem<CAPI>, UNKNOWN, std::vector<ConcreteCompilerType*>{ UNKNOWN, UNKNOWN },
CAPI);
list_cls->giveAttr("__getitem__", new BoxedFunction(getitem)); list_cls->giveAttr("__getitem__", new BoxedFunction(getitem));
list_cls->giveAttr("__getslice__", new BoxedFunction(boxRTFunction((void*)listGetslice, LIST, 3))); list_cls->giveAttr("__getslice__", new BoxedFunction(boxRTFunction((void*)listGetslice, LIST, 3)));
......
...@@ -305,6 +305,10 @@ extern "C" void raiseIndexErrorStr(const char* typeName) { ...@@ -305,6 +305,10 @@ extern "C" void raiseIndexErrorStr(const char* typeName) {
raiseExcHelper(IndexError, "%s index out of range", typeName); raiseExcHelper(IndexError, "%s index out of range", typeName);
} }
extern "C" void raiseIndexErrorStrCapi(const char* typeName) noexcept {
PyErr_Format(IndexError, "%s index out of range", typeName);
}
extern "C" void raiseNotIterableError(const char* typeName) { extern "C" void raiseNotIterableError(const char* typeName) {
raiseExcHelper(TypeError, "'%s' object is not iterable", typeName); raiseExcHelper(TypeError, "'%s' object is not iterable", typeName);
} }
...@@ -1363,7 +1367,8 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS ...@@ -1363,7 +1367,8 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS
} }
// Helper function: make sure that a capi function either returned a non-error value, or // Helper function: make sure that a capi function either returned a non-error value, or
// it set an exception. // it set an exception. This is only needed in specialized situations; usually the "error
// return without exception set" state can just be passed up to the caller.
static void ensureValidCapiReturn(Box* r) { static void ensureValidCapiReturn(Box* r) {
if (!r) if (!r)
ensureCAPIExceptionSet(); ensureCAPIExceptionSet();
...@@ -3011,8 +3016,27 @@ void rearrangeArguments(ParamReceiveSpec paramspec, const ParamNames* param_name ...@@ -3011,8 +3016,27 @@ void rearrangeArguments(ParamReceiveSpec paramspec, const ParamNames* param_name
// Fast path: if it's a simple-enough call, we don't have to do anything special. On a simple // Fast path: if it's a simple-enough call, we don't have to do anything special. On a simple
// django-admin test this covers something like 93% of all calls to callFunc. // django-admin test this covers something like 93% of all calls to callFunc.
if (argspec.num_keywords == 0 && argspec.has_starargs == paramspec.takes_varargs && !argspec.has_kwargs if (argspec.num_keywords == 0 && argspec.has_starargs == paramspec.takes_varargs && !argspec.has_kwargs
&& !paramspec.takes_kwargs && argspec.num_args == paramspec.num_args) { && argspec.num_args == paramspec.num_args && (!paramspec.takes_kwargs || paramspec.kwargsIndex() < 3)) {
assert(num_output_args == num_passed_args);
// TODO could also do this for empty varargs
if (paramspec.takes_kwargs) {
assert(num_output_args == num_passed_args + 1);
int idx = paramspec.kwargsIndex();
assert(idx < 3);
getArg(idx, arg1, arg2, arg3, NULL) = NULL; // pass NULL for kwargs
if (rewrite_args) {
if (idx == 0)
rewrite_args->arg1 = rewrite_args->rewriter->loadConst(0);
else if (idx == 1)
rewrite_args->arg2 = rewrite_args->rewriter->loadConst(0);
else if (idx == 2)
rewrite_args->arg3 = rewrite_args->rewriter->loadConst(0);
else
abort();
}
} else {
assert(num_output_args == num_passed_args);
}
// If the caller passed starargs, we can only pass those directly to the callee if it's a tuple, // If the caller passed starargs, we can only pass those directly to the callee if it's a tuple,
// since otherwise modifications by the callee would be visible to the caller (hence why varargs // since otherwise modifications by the callee would be visible to the caller (hence why varargs
...@@ -4463,11 +4487,6 @@ Box* callItemOrSliceAttr(Box* target, BoxedString* item_str, BoxedString* slice_ ...@@ -4463,11 +4487,6 @@ Box* callItemOrSliceAttr(Box* target, BoxedString* item_str, BoxedString* slice_
template <ExceptionStyle S> template <ExceptionStyle S>
Box* getitemInternal(Box* target, Box* slice, GetitemRewriteArgs* rewrite_args) noexcept(S == CAPI) { Box* getitemInternal(Box* target, Box* slice, GetitemRewriteArgs* rewrite_args) noexcept(S == CAPI) {
if (S == CAPI) {
assert(!rewrite_args && "implement me");
rewrite_args = NULL;
}
// The PyObject_GetItem logic is: // The PyObject_GetItem logic is:
// - call mp_subscript if it exists // - call mp_subscript if it exists
// - if tp_as_sequence exists, try using that (with a number of conditions) // - if tp_as_sequence exists, try using that (with a number of conditions)
...@@ -4479,7 +4498,6 @@ Box* getitemInternal(Box* target, Box* slice, GetitemRewriteArgs* rewrite_args) ...@@ -4479,7 +4498,6 @@ Box* getitemInternal(Box* target, Box* slice, GetitemRewriteArgs* rewrite_args)
PyMappingMethods* m = target->cls->tp_as_mapping; PyMappingMethods* m = target->cls->tp_as_mapping;
if (m && m->mp_subscript && m->mp_subscript != slot_mp_subscript) { if (m && m->mp_subscript && m->mp_subscript != slot_mp_subscript) {
if (rewrite_args) { if (rewrite_args) {
assert(S == CXX);
RewriterVar* r_obj = rewrite_args->target; RewriterVar* r_obj = rewrite_args->target;
RewriterVar* r_slice = rewrite_args->slice; RewriterVar* r_slice = rewrite_args->slice;
RewriterVar* r_cls = r_obj->getAttr(offsetof(Box, cls)); RewriterVar* r_cls = r_obj->getAttr(offsetof(Box, cls));
...@@ -4493,7 +4511,8 @@ Box* getitemInternal(Box* target, Box* slice, GetitemRewriteArgs* rewrite_args) ...@@ -4493,7 +4511,8 @@ Box* getitemInternal(Box* target, Box* slice, GetitemRewriteArgs* rewrite_args)
// support calling a RewriterVar (can only call fixed function addresses). // support calling a RewriterVar (can only call fixed function addresses).
r_m->addAttrGuard(offsetof(PyMappingMethods, mp_subscript), (intptr_t)m->mp_subscript); r_m->addAttrGuard(offsetof(PyMappingMethods, mp_subscript), (intptr_t)m->mp_subscript);
RewriterVar* r_rtn = rewrite_args->rewriter->call(true, (void*)m->mp_subscript, r_obj, r_slice); RewriterVar* r_rtn = rewrite_args->rewriter->call(true, (void*)m->mp_subscript, r_obj, r_slice);
rewrite_args->rewriter->call(true, (void*)checkAndThrowCAPIException); if (S == CXX)
rewrite_args->rewriter->call(true, (void*)checkAndThrowCAPIException);
rewrite_args->out_success = true; rewrite_args->out_success = true;
rewrite_args->out_rtn = r_rtn; rewrite_args->out_rtn = r_rtn;
} }
...@@ -4503,6 +4522,11 @@ Box* getitemInternal(Box* target, Box* slice, GetitemRewriteArgs* rewrite_args) ...@@ -4503,6 +4522,11 @@ Box* getitemInternal(Box* target, Box* slice, GetitemRewriteArgs* rewrite_args)
return r; return r;
} }
if (S == CAPI) {
// assert(!rewrite_args && "implement me");
rewrite_args = NULL;
}
static BoxedString* getitem_str = internStringImmortal("__getitem__"); static BoxedString* getitem_str = internStringImmortal("__getitem__");
static BoxedString* getslice_str = internStringImmortal("__getslice__"); static BoxedString* getslice_str = internStringImmortal("__getslice__");
...@@ -4596,6 +4620,39 @@ extern "C" Box* getitem(Box* target, Box* slice) { ...@@ -4596,6 +4620,39 @@ extern "C" Box* getitem(Box* target, Box* slice) {
return rtn; return rtn;
} }
// target[slice]
extern "C" Box* getitem_capi(Box* target, Box* slice) noexcept {
STAT_TIMER(t0, "us_timer_slowpath_getitem", 10);
// This possibly could just be represented as a single callattr; the only tricky part
// are the error messages.
// Ex "(1)[1]" and "(1).__getitem__(1)" give different error messages.
static StatCounter slowpath_getitem("slowpath_getitem");
slowpath_getitem.log();
std::unique_ptr<Rewriter> rewriter(
Rewriter::createRewriter(__builtin_extract_return_addr(__builtin_return_address(0)), 2, "getitem"));
Box* rtn;
if (rewriter.get()) {
GetitemRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0), rewriter->getArg(1),
rewriter->getReturnDestination());
rtn = getitemInternal<CAPI>(target, slice, &rewrite_args);
if (!rewrite_args.out_success) {
rewriter.reset(NULL);
} else {
rewriter->commitReturning(rewrite_args.out_rtn);
}
} else {
rtn = getitemInternal<CAPI>(target, slice, NULL);
}
return rtn;
}
// target[slice] = value // target[slice] = value
extern "C" void setitem(Box* target, Box* slice, Box* value) { extern "C" void setitem(Box* target, Box* slice, Box* value) {
STAT_TIMER(t0, "us_timer_slowpath_setitem", 10); STAT_TIMER(t0, "us_timer_slowpath_setitem", 10);
......
...@@ -35,6 +35,7 @@ class BoxedTuple; ...@@ -35,6 +35,7 @@ class BoxedTuple;
ExcInfo excInfoForRaise(Box*, Box*, Box*); ExcInfo excInfoForRaise(Box*, Box*, Box*);
extern "C" void raise0() __attribute__((__noreturn__)); extern "C" void raise0() __attribute__((__noreturn__));
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;
void raiseExc(Box* exc_obj) __attribute__((__noreturn__)); void raiseExc(Box* exc_obj) __attribute__((__noreturn__));
void _printStacktrace(); void _printStacktrace();
...@@ -82,6 +83,7 @@ extern "C" i64 unboxedLen(Box* obj); ...@@ -82,6 +83,7 @@ extern "C" i64 unboxedLen(Box* obj);
extern "C" Box* binop(Box* lhs, Box* rhs, int op_type); extern "C" Box* binop(Box* lhs, Box* rhs, int op_type);
extern "C" Box* augbinop(Box* lhs, Box* rhs, int op_type); extern "C" Box* augbinop(Box* lhs, Box* rhs, int op_type);
extern "C" Box* getitem(Box* value, Box* slice); extern "C" Box* getitem(Box* value, Box* slice);
extern "C" Box* getitem_capi(Box* value, Box* slice) noexcept;
extern "C" void setitem(Box* target, Box* slice, Box* value); extern "C" void setitem(Box* target, Box* slice, Box* value);
extern "C" void delitem(Box* target, Box* slice); extern "C" void delitem(Box* target, Box* slice);
extern "C" Box* getclsattr(Box* obj, BoxedString* attr); extern "C" Box* getclsattr(Box* obj, BoxedString* attr);
...@@ -158,6 +160,7 @@ extern "C" void raiseAttributeErrorStrCapi(const char* typeName, llvm::StringRef ...@@ -158,6 +160,7 @@ extern "C" void raiseAttributeErrorStrCapi(const char* typeName, llvm::StringRef
extern "C" void raiseAttributeErrorCapi(Box* obj, 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 raiseNotIterableError(const char* typeName) __attribute__((__noreturn__));
extern "C" void raiseIndexErrorStr(const char* typeName) __attribute__((__noreturn__)); extern "C" void raiseIndexErrorStr(const char* typeName) __attribute__((__noreturn__));
extern "C" void raiseIndexErrorStrCapi(const char* typeName) noexcept;
Box* typeCall(Box*, BoxedTuple*, BoxedDict*); Box* typeCall(Box*, BoxedTuple*, BoxedDict*);
Box* type_new(BoxedClass* metatype, Box* args, Box* kwds) noexcept; Box* type_new(BoxedClass* metatype, Box* args, Box* kwds) noexcept;
......
...@@ -272,6 +272,21 @@ extern "C" void raise3(Box* arg0, Box* arg1, Box* arg2) { ...@@ -272,6 +272,21 @@ extern "C" void raise3(Box* arg0, Box* arg1, Box* arg2) {
throw exc_info; throw exc_info;
} }
extern "C" void raise3_capi(Box* arg0, Box* arg1, Box* arg2) noexcept {
bool reraise = arg2 != NULL && arg2 != None;
ExcInfo exc_info(NULL, NULL, NULL);
try {
exc_info = excInfoForRaise(arg0, arg1, arg2);
exc_info.reraise = reraise;
} catch (ExcInfo e) {
exc_info = e;
}
assert(!exc_info.reraise); // would get thrown away
PyErr_Restore(exc_info.type, exc_info.value, exc_info.traceback);
}
void raiseExcHelper(BoxedClass* cls, Box* arg) { void raiseExcHelper(BoxedClass* cls, Box* arg) {
Box* exc_obj = runtimeCall(cls, ArgPassSpec(1), arg, NULL, NULL, NULL, NULL); Box* exc_obj = runtimeCall(cls, ArgPassSpec(1), arg, NULL, NULL, NULL, NULL);
raiseExc(exc_obj); raiseExc(exc_obj);
......
...@@ -2216,7 +2216,15 @@ Box* strEncode(BoxedString* self, Box* encoding, Box* error) { ...@@ -2216,7 +2216,15 @@ Box* strEncode(BoxedString* self, Box* encoding, Box* error) {
return result; return result;
} }
extern "C" Box* strGetitem(BoxedString* self, Box* slice) { template <ExceptionStyle S> Box* strGetitem(BoxedString* self, Box* slice) {
if (S == CAPI) {
try {
return strGetitem<CXX>(self, slice);
} catch (ExcInfo e) {
setCAPIException(e);
return NULL;
}
}
assert(PyString_Check(self)); assert(PyString_Check(self));
if (PyIndex_Check(slice)) { if (PyIndex_Check(slice)) {
...@@ -2760,7 +2768,9 @@ void setupStr() { ...@@ -2760,7 +2768,9 @@ void setupStr() {
str_cls->giveAttr("center", str_cls->giveAttr("center",
new BoxedFunction(boxRTFunction((void*)strCenter, UNKNOWN, 3, 1, false, false), { spaceChar })); new BoxedFunction(boxRTFunction((void*)strCenter, UNKNOWN, 3, 1, false, false), { spaceChar }));
str_cls->giveAttr("__getitem__", new BoxedFunction(boxRTFunction((void*)strGetitem, STR, 2))); auto str_getitem = boxRTFunction((void*)strGetitem<CXX>, STR, 2, ParamNames::empty(), CXX);
addRTFunction(str_getitem, (void*)strGetitem<CAPI>, STR, CAPI);
str_cls->giveAttr("__getitem__", new BoxedFunction(str_getitem));
str_cls->giveAttr("__getslice__", new BoxedFunction(boxRTFunction((void*)strGetslice, STR, 3))); str_cls->giveAttr("__getslice__", new BoxedFunction(boxRTFunction((void*)strGetslice, STR, 3)));
......
...@@ -114,7 +114,7 @@ Box* BoxedTraceback::getLines(Box* b) { ...@@ -114,7 +114,7 @@ Box* BoxedTraceback::getLines(Box* b) {
} }
void BoxedTraceback::here(LineInfo lineInfo, Box** tb) { void BoxedTraceback::here(LineInfo lineInfo, Box** tb) {
*tb = new BoxedTraceback(lineInfo, *tb); *tb = new BoxedTraceback(std::move(lineInfo), *tb);
} }
void setupTraceback() { void setupTraceback() {
......
...@@ -31,7 +31,7 @@ public: ...@@ -31,7 +31,7 @@ public:
LineInfo line; LineInfo line;
Box* py_lines; Box* py_lines;
BoxedTraceback(LineInfo line, Box* tb_next) : tb_next(tb_next), line(line), py_lines(NULL) {} BoxedTraceback(LineInfo line, Box* tb_next) : tb_next(tb_next), line(std::move(line)), py_lines(NULL) {}
DEFAULT_CLASS(traceback_cls); DEFAULT_CLASS(traceback_cls);
......
...@@ -135,7 +135,16 @@ int BoxedTuple::Resize(BoxedTuple** pv, size_t newsize) noexcept { ...@@ -135,7 +135,16 @@ int BoxedTuple::Resize(BoxedTuple** pv, size_t newsize) noexcept {
return 0; return 0;
} }
Box* tupleGetitem(BoxedTuple* self, Box* slice) { template <ExceptionStyle S> Box* tupleGetitem(BoxedTuple* self, Box* slice) {
if (S == CAPI) {
try {
return tupleGetitem<CXX>(self, slice);
} catch (ExcInfo e) {
setCAPIException(e);
return NULL;
}
}
assert(self->cls == tuple_cls); assert(self->cls == tuple_cls);
if (PyIndex_Check(slice)) { if (PyIndex_Check(slice)) {
...@@ -555,7 +564,10 @@ void setupTuple() { ...@@ -555,7 +564,10 @@ void setupTuple() {
CLFunction* getitem = createRTFunction(2, 0, 0, 0); CLFunction* getitem = createRTFunction(2, 0, 0, 0);
addRTFunction(getitem, (void*)tupleGetitemInt, UNKNOWN, std::vector<ConcreteCompilerType*>{ UNKNOWN, BOXED_INT }); addRTFunction(getitem, (void*)tupleGetitemInt, UNKNOWN, std::vector<ConcreteCompilerType*>{ UNKNOWN, BOXED_INT });
addRTFunction(getitem, (void*)tupleGetitemSlice, UNKNOWN, std::vector<ConcreteCompilerType*>{ UNKNOWN, SLICE }); addRTFunction(getitem, (void*)tupleGetitemSlice, UNKNOWN, std::vector<ConcreteCompilerType*>{ UNKNOWN, SLICE });
addRTFunction(getitem, (void*)tupleGetitem, UNKNOWN, std::vector<ConcreteCompilerType*>{ UNKNOWN, UNKNOWN }); addRTFunction(getitem, (void*)tupleGetitem<CXX>, UNKNOWN, std::vector<ConcreteCompilerType*>{ UNKNOWN, UNKNOWN },
CXX);
addRTFunction(getitem, (void*)tupleGetitem<CAPI>, UNKNOWN, std::vector<ConcreteCompilerType*>{ UNKNOWN, UNKNOWN },
CAPI);
tuple_cls->giveAttr("__getitem__", new BoxedFunction(getitem)); tuple_cls->giveAttr("__getitem__", new BoxedFunction(getitem));
tuple_cls->giveAttr("__contains__", new BoxedFunction(boxRTFunction((void*)tupleContains, BOXED_BOOL, 2))); tuple_cls->giveAttr("__contains__", new BoxedFunction(boxRTFunction((void*)tupleContains, BOXED_BOOL, 2)));
......
# skip-if: True
# expected: fail # expected: fail
# - CPython calls subclasscheck twice, while we call it once. # - CPython calls subclasscheck twice, while we call it once.
# Looks like this is because CPython calls PyErr_NormalizeException # Looks like this is because CPython calls PyErr_NormalizeException
......
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