Commit ae770511 authored by Kevin Modzelewski's avatar Kevin Modzelewski

capi exceptions for getitems

Less helpful than I thought for now -- the KeyErrors are thrown
by a custom class that does `raise KeyError`, so we won't benefit
from this until we can have jitted code throw (not just receive)
capi exceptions.
parent fc02e94c
......@@ -337,6 +337,10 @@ public:
CompilerVariable* slice) override {
ConcreteCompilerVariable* converted_slice = slice->makeConverted(emitter, slice->getBoxType());
ExceptionStyle target_exception_style = CXX;
if (info.unw_info.capi_exc_dest)
target_exception_style = CAPI;
bool do_patchpoint = ENABLE_ICGETITEMS;
llvm::Value* rtn;
if (do_patchpoint) {
......@@ -346,13 +350,20 @@ public:
llvm_args.push_back(var->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);
} 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);
if (target_exception_style == CAPI)
emitter.checkAndPropagateCapiException(info.unw_info, rtn, getNullPtr(g.llvm_value_type_ptr));
return new ConcreteCompilerVariable(UNKNOWN, rtn, true);
}
......@@ -1550,15 +1561,27 @@ public:
if (!canStaticallyResolveGetattrs())
return NULL;
ExceptionStyle exception_style = CXX;
if (info.unw_info.capi_exc_dest)
exception_style = CAPI;
Box* rtattr = cls->getattr(attr);
if (rtattr == NULL) {
if (no_attribute) {
*no_attribute = true;
} else {
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();
}
......@@ -1589,6 +1612,9 @@ public:
cf = cl->versions[i];
assert(cf->spec->arg_types.size() == cl->numReceivedArgs());
if (cf->exception_style != exception_style)
continue;
bool fits = true;
for (int j = 0; j < args.size(); j++) {
if (!args[j]->canConvertTo(cf->spec->arg_types[j + 1])) {
......@@ -1603,8 +1629,12 @@ public:
break;
}
assert(found);
assert(cf->code);
if (!found && exception_style == CAPI) {
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;
RELEASE_ASSERT(paramspec.num_args == cl->numReceivedArgs(), "");
......
......@@ -136,7 +136,7 @@ ExceptionStyle IRGenState::getLandingpadStyle(AST_Invoke* invoke) {
return r;
}
if (expr->type == AST_TYPE::Attribute) {
if (expr->type == AST_TYPE::Attribute || expr->type == AST_TYPE::Subscript) {
r = CAPI;
// printf("Doing a capi exception to %d\n", invoke->exc_dest->idx);
return r;
......
......@@ -199,6 +199,7 @@ void initGlobalFuncs(GlobalState& g) {
GET(setattr);
GET(delattr);
GET(getitem);
GET(getitem_capi);
GET(setitem);
GET(delitem);
GET(getGlobal);
......
......@@ -36,8 +36,8 @@ struct GlobalFuncs {
*boxBool, *unboxBool, *createTuple, *createDict, *createList, *createSlice, *createUserClass, *createClosure,
*createGenerator, *createSet;
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;
*augbinop, *unboxedLen, *getitem, *getitem_capi, *getclsattr, *getGlobal, *setitem, *unaryop, *import,
*importFrom, *importStar, *repr, *str, *strOrUnicode, *exceptionMatches, *yield, *getiterHelper, *hasnext;
llvm::Value* unpackIntoArray, *raiseAttributeError, *raiseAttributeErrorStr, *raiseAttributeErrorCapi,
*raiseAttributeErrorStrCapi, *raiseNotIterableError, *raiseIndexErrorStr, *assertNameDefined, *assertFail,
......
......@@ -746,7 +746,9 @@ void setupDict() {
dict_cls->giveAttr("setdefault",
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("__delitem__", new BoxedFunction(boxRTFunction((void*)dictDelitem, UNKNOWN, 2)));
dict_cls->giveAttr("__contains__", new BoxedFunction(boxRTFunction((void*)dictContains, BOXED_BOOL, 2)));
......
......@@ -83,6 +83,7 @@ void force() {
FORCE(augbinop);
FORCE(unboxedLen);
FORCE(getitem);
FORCE(getitem_capi);
FORCE(getclsattr);
FORCE(getGlobal);
FORCE(delGlobal);
......
......@@ -4481,11 +4481,6 @@ Box* callItemOrSliceAttr(Box* target, BoxedString* item_str, BoxedString* slice_
template <ExceptionStyle S>
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:
// - call mp_subscript if it exists
// - if tp_as_sequence exists, try using that (with a number of conditions)
......@@ -4497,7 +4492,6 @@ Box* getitemInternal(Box* target, Box* slice, GetitemRewriteArgs* rewrite_args)
PyMappingMethods* m = target->cls->tp_as_mapping;
if (m && m->mp_subscript && m->mp_subscript != slot_mp_subscript) {
if (rewrite_args) {
assert(S == CXX);
RewriterVar* r_obj = rewrite_args->target;
RewriterVar* r_slice = rewrite_args->slice;
RewriterVar* r_cls = r_obj->getAttr(offsetof(Box, cls));
......@@ -4511,7 +4505,8 @@ Box* getitemInternal(Box* target, Box* slice, GetitemRewriteArgs* rewrite_args)
// support calling a RewriterVar (can only call fixed function addresses).
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);
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_rtn = r_rtn;
}
......@@ -4521,6 +4516,11 @@ Box* getitemInternal(Box* target, Box* slice, GetitemRewriteArgs* rewrite_args)
return r;
}
if (S == CAPI) {
assert(!rewrite_args && "implement me");
rewrite_args = NULL;
}
static BoxedString* getitem_str = internStringImmortal("__getitem__");
static BoxedString* getslice_str = internStringImmortal("__getslice__");
......@@ -4614,6 +4614,39 @@ extern "C" Box* getitem(Box* target, Box* slice) {
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
extern "C" void setitem(Box* target, Box* slice, Box* value) {
STAT_TIMER(t0, "us_timer_slowpath_setitem", 10);
......
......@@ -83,6 +83,7 @@ extern "C" i64 unboxedLen(Box* obj);
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* 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 delitem(Box* target, Box* slice);
extern "C" Box* getclsattr(Box* obj, BoxedString* attr);
......
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