Commit 2a0955bb authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #949 from kmod/return_conventions

Add more asserts to aggressively enforce return conventions
parents 6d143b9f 7d839c02
...@@ -277,6 +277,8 @@ public: ...@@ -277,6 +277,8 @@ public:
assert(rewriter); assert(rewriter);
} }
Rewriter* getRewriter() { return rewriter; }
friend class Rewriter; friend class Rewriter;
friend class JitFragmentWriter; friend class JitFragmentWriter;
}; };
......
...@@ -908,7 +908,11 @@ Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs* ...@@ -908,7 +908,11 @@ Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs*
getattr = typeLookup(self->cls, _getattr_str, NULL); getattr = typeLookup(self->cls, _getattr_str, NULL);
if (getattr == NULL) { if (getattr == NULL) {
assert(!rewrite_args || !rewrite_args->out_success); if (rewrite_args) {
// Don't bother rewriting this case:
assert(!rewrite_args->isSuccessful());
rewrite_args = NULL;
}
/* No __getattr__ hook: use a simpler dispatcher */ /* No __getattr__ hook: use a simpler dispatcher */
self->cls->tp_getattro = slot_tp_getattro; self->cls->tp_getattro = slot_tp_getattro;
...@@ -931,13 +935,12 @@ Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs* ...@@ -931,13 +935,12 @@ Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs*
GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, r_obj_cls, Location::any()); GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, r_obj_cls, Location::any());
getattribute = typeLookup(self->cls, _getattribute_str, &grewrite_args); getattribute = typeLookup(self->cls, _getattribute_str, &grewrite_args);
if (!grewrite_args.out_success) if (!grewrite_args.isSuccessful())
rewrite_args = NULL; rewrite_args = NULL;
else if (getattribute) { else if (getattribute) {
assert(grewrite_args.out_return_convention == GetattrRewriteArgs::VALID_RETURN); r_getattribute = grewrite_args.getReturn(ReturnConvention::HAS_RETURN);
r_getattribute = grewrite_args.out_rtn;
} else { } else {
assert(grewrite_args.out_return_convention == GetattrRewriteArgs::NO_RETURN); grewrite_args.assertReturnConvention(ReturnConvention::NO_RETURN);
} }
} else { } else {
getattribute = typeLookup(self->cls, _getattribute_str, NULL); getattribute = typeLookup(self->cls, _getattribute_str, NULL);
...@@ -973,35 +976,38 @@ Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs* ...@@ -973,35 +976,38 @@ Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs*
throw e; throw e;
} }
grewrite_args.out_success = false; if (grewrite_args.isSuccessful()) {
grewrite_args.getReturn(); // to make the asserts happy
grewrite_args.clearReturn();
}
res = NULL; res = NULL;
} }
if (!grewrite_args.out_success) if (!grewrite_args.isSuccessful())
rewrite_args = NULL; rewrite_args = NULL;
else if (res) { else {
rewrite_args->out_rtn = grewrite_args.out_rtn; RewriterVar* rtn;
rewrite_args->out_return_convention = grewrite_args.out_return_convention; ReturnConvention return_convention;
} std::tie(rtn, return_convention) = grewrite_args.getReturn();
// Guarding here is a bit tricky, since we need to make sure that we call getattr if (return_convention == ReturnConvention::HAS_RETURN) {
// (or not) at the right times.
// Right now this section is a bit conservative.
if (rewrite_args) {
if (grewrite_args.out_return_convention == GetattrRewriteArgs::NO_RETURN) {
// Do nothing
} else if (grewrite_args.out_return_convention == GetattrRewriteArgs::VALID_RETURN) {
// TODO we should have a HAS_RETURN that takes out the NULL case
assert(res); assert(res);
if (res) rewrite_args->setReturn(rtn, ReturnConvention::HAS_RETURN);
grewrite_args.out_rtn->addGuardNotEq(0); return res;
else } else if (return_convention == ReturnConvention::NO_RETURN) {
grewrite_args.out_rtn->addGuard(0); assert(!res);
} else if (grewrite_args.out_return_convention == GetattrRewriteArgs::NOEXC_POSSIBLE) { } else if (return_convention == ReturnConvention::CAPI_RETURN) {
// TODO maybe we could handle this // If we get a CAPI return, we probably did a function call, and these guards
rewrite_args = NULL; // will probably just make the rewrite fail:
if (res) {
rtn->addGuardNotEq(0);
rewrite_args->setReturn(rtn, ReturnConvention::HAS_RETURN);
return res;
} else
rtn->addGuard(0);
} else { } else {
RELEASE_ASSERT(0, "%d", grewrite_args.out_return_convention); assert(return_convention == ReturnConvention::NOEXC_POSSIBLE);
rewrite_args = NULL;
} }
} }
} else { } else {
...@@ -1044,8 +1050,7 @@ Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs* ...@@ -1044,8 +1050,7 @@ Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs*
// doesn't exist. // doesn't exist.
if (res) { if (res) {
if (rewrite_args) assert(!rewrite_args); // should have been handled already
rewrite_args->out_success = true;
return res; return res;
} }
...@@ -1059,7 +1064,7 @@ Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs* ...@@ -1059,7 +1064,7 @@ Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs*
// - we have no way of signalling that "we didn't get an attribute this time but that may be different // - we have no way of signalling that "we didn't get an attribute this time but that may be different
// in future executions through the IC". // in future executions through the IC".
// I think this should only end up mattering anyway if the getattr site throws every single time. // I think this should only end up mattering anyway if the getattr site throws every single time.
CallRewriteArgs crewrite_args(rewrite_args->rewriter, rewrite_args->obj, rewrite_args->destination); CallattrRewriteArgs crewrite_args(rewrite_args->rewriter, rewrite_args->obj, rewrite_args->destination);
assert(PyString_CHECK_INTERNED(name) == SSTATE_INTERNED_IMMORTAL); assert(PyString_CHECK_INTERNED(name) == SSTATE_INTERNED_IMMORTAL);
crewrite_args.arg1 = rewrite_args->rewriter->loadConst((intptr_t)name, Location::forArg(1)); crewrite_args.arg1 = rewrite_args->rewriter->loadConst((intptr_t)name, Location::forArg(1));
...@@ -1067,11 +1072,10 @@ Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs* ...@@ -1067,11 +1072,10 @@ Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs*
NULL, NULL, NULL, NULL); NULL, NULL, NULL, NULL);
assert(res || S == CAPI); assert(res || S == CAPI);
if (!crewrite_args.out_success) if (!crewrite_args.isSuccessful())
rewrite_args = NULL; rewrite_args = NULL;
else { else {
rewrite_args->out_rtn = crewrite_args.out_rtn; rewrite_args->setReturn(crewrite_args.getReturn());
rewrite_args->out_return_convention = GetattrRewriteArgs::VALID_RETURN;
} }
} else { } else {
// TODO: we already fetched the getattr attribute, it would be faster to call it rather than do // TODO: we already fetched the getattr attribute, it would be faster to call it rather than do
...@@ -1084,8 +1088,6 @@ Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs* ...@@ -1084,8 +1088,6 @@ Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs*
assert(res || S == CAPI); assert(res || S == CAPI);
} }
if (rewrite_args)
rewrite_args->out_success = true;
return res; return res;
} }
// Force instantiation of the template // Force instantiation of the template
......
...@@ -569,16 +569,15 @@ Box* getattrFuncInternal(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ...@@ -569,16 +569,15 @@ Box* getattrFuncInternal(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args,
GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, rewrite_args->arg1, rewrite_args->destination); GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, rewrite_args->arg1, rewrite_args->destination);
rtn = getattrInternal<CAPI>(obj, str, &grewrite_args); rtn = getattrInternal<CAPI>(obj, str, &grewrite_args);
// TODO could make the return valid in the NOEXC_POSSIBLE case via a helper // TODO could make the return valid in the NOEXC_POSSIBLE case via a helper
if (!grewrite_args.out_success || grewrite_args.out_return_convention == GetattrRewriteArgs::NOEXC_POSSIBLE) if (!grewrite_args.isSuccessful())
rewrite_args = NULL; rewrite_args = NULL;
else { else {
if (!rtn && !PyErr_Occurred()) { ReturnConvention return_convention;
assert(grewrite_args.out_return_convention == GetattrRewriteArgs::NO_RETURN); std::tie(r_rtn, return_convention) = grewrite_args.getReturn();
// Convert to NOEXC_POSSIBLE:
if (return_convention == ReturnConvention::NO_RETURN)
r_rtn = rewrite_args->rewriter->loadConst(0); r_rtn = rewrite_args->rewriter->loadConst(0);
} else {
assert(grewrite_args.out_return_convention == GetattrRewriteArgs::VALID_RETURN);
r_rtn = grewrite_args.out_rtn;
}
} }
} else { } else {
rtn = getattrInternal<CAPI>(obj, str, NULL); rtn = getattrInternal<CAPI>(obj, str, NULL);
...@@ -681,16 +680,15 @@ Box* hasattrFuncInternal(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ...@@ -681,16 +680,15 @@ Box* hasattrFuncInternal(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args,
if (rewrite_args) { if (rewrite_args) {
GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, rewrite_args->arg1, rewrite_args->destination); GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, rewrite_args->arg1, rewrite_args->destination);
rtn = getattrInternal<CAPI>(obj, str, &grewrite_args); rtn = getattrInternal<CAPI>(obj, str, &grewrite_args);
if (!grewrite_args.out_success || grewrite_args.out_return_convention == GetattrRewriteArgs::NOEXC_POSSIBLE) if (!grewrite_args.isSuccessful())
rewrite_args = NULL; rewrite_args = NULL;
else { else {
if (!rtn && !PyErr_Occurred()) { ReturnConvention return_convention;
assert(grewrite_args.out_return_convention == GetattrRewriteArgs::NO_RETURN); std::tie(r_rtn, return_convention) = grewrite_args.getReturn();
// Convert to NOEXC_POSSIBLE:
if (return_convention == ReturnConvention::NO_RETURN)
r_rtn = rewrite_args->rewriter->loadConst(0); r_rtn = rewrite_args->rewriter->loadConst(0);
} else {
assert(grewrite_args.out_return_convention == GetattrRewriteArgs::VALID_RETURN);
r_rtn = grewrite_args.out_rtn;
}
} }
} else { } else {
rtn = getattrInternal<CAPI>(obj, str, NULL); rtn = getattrInternal<CAPI>(obj, str, NULL);
......
...@@ -32,15 +32,20 @@ BoxedClass* classobj_cls, *instance_cls; ...@@ -32,15 +32,20 @@ BoxedClass* classobj_cls, *instance_cls;
static Box* classLookup(BoxedClassobj* cls, BoxedString* attr, GetattrRewriteArgs* rewrite_args = NULL) { static Box* classLookup(BoxedClassobj* cls, BoxedString* attr, GetattrRewriteArgs* rewrite_args = NULL) {
if (rewrite_args) if (rewrite_args)
assert(!rewrite_args->out_success); assert(!rewrite_args->isSuccessful());
Box* r = cls->getattr(attr, rewrite_args); Box* r = cls->getattr(attr, rewrite_args);
if (r) if (r) {
if (rewrite_args)
rewrite_args->assertReturnConvention(ReturnConvention::HAS_RETURN);
return r; return r;
}
if (rewrite_args) { if (rewrite_args) {
// abort rewriting because we currenly don't guard the particular 'bases' hierarchy if (rewrite_args->isSuccessful()) {
rewrite_args->out_success = false; rewrite_args->getReturn(); // just to make the asserts happy
rewrite_args->clearReturn();
}
rewrite_args = NULL; rewrite_args = NULL;
} }
...@@ -322,62 +327,71 @@ Box* classobjRepr(Box* _obj) { ...@@ -322,62 +327,71 @@ Box* classobjRepr(Box* _obj) {
// Analogous to CPython's instance_getattr2 // Analogous to CPython's instance_getattr2
static Box* instanceGetattributeSimple(BoxedInstance* inst, BoxedString* attr_str, static Box* instanceGetattributeSimple(BoxedInstance* inst, BoxedString* attr_str,
GetattrRewriteArgs* rewriter_args = NULL) { GetattrRewriteArgs* rewrite_args = NULL) {
Box* r = inst->getattr(attr_str, rewriter_args); Box* r = inst->getattr(attr_str, rewrite_args);
if (r) if (r) {
if (rewrite_args)
rewrite_args->assertReturnConvention(ReturnConvention::HAS_RETURN);
return r; return r;
}
RewriterVar* r_inst = NULL; RewriterVar* r_inst = NULL;
RewriterVar* r_inst_cls = NULL; RewriterVar* r_inst_cls = NULL;
if (rewriter_args) { if (rewrite_args) {
if (!rewriter_args->out_success) if (!rewrite_args->isSuccessful())
rewriter_args = NULL; rewrite_args = NULL;
else { else {
rewriter_args->out_success = false; rewrite_args->assertReturnConvention(ReturnConvention::NO_RETURN);
r_inst = rewriter_args->obj; rewrite_args->clearReturn();
r_inst = rewrite_args->obj;
r_inst_cls = r_inst->getAttr(offsetof(BoxedInstance, inst_cls)); r_inst_cls = r_inst->getAttr(offsetof(BoxedInstance, inst_cls));
} }
} }
GetattrRewriteArgs grewriter_inst_args(rewriter_args ? rewriter_args->rewriter : NULL, r_inst_cls, GetattrRewriteArgs grewriter_inst_args(rewrite_args ? rewrite_args->rewriter : NULL, r_inst_cls,
rewriter_args ? rewriter_args->rewriter->getReturnDestination() rewrite_args ? rewrite_args->rewriter->getReturnDestination() : Location());
: Location()); r = classLookup(inst->inst_cls, attr_str, rewrite_args ? &grewriter_inst_args : NULL);
r = classLookup(inst->inst_cls, attr_str, rewriter_args ? &grewriter_inst_args : NULL); if (!grewriter_inst_args.isSuccessful())
if (!grewriter_inst_args.out_success) rewrite_args = NULL;
rewriter_args = NULL;
else
assert(grewriter_inst_args.out_return_convention == GetattrRewriteArgs::VALID_RETURN);
if (r) { if (r) {
Box* rtn = processDescriptor(r, inst, inst->inst_cls); Box* rtn = processDescriptor(r, inst, inst->inst_cls);
if (rewriter_args) { if (rewrite_args) {
RewriterVar* r_rtn = rewriter_args->rewriter->call(true, (void*)processDescriptor, RewriterVar* r_rtn = rewrite_args->rewriter->call(
grewriter_inst_args.out_rtn, r_inst, r_inst_cls); true, (void*)processDescriptor, grewriter_inst_args.getReturn(ReturnConvention::HAS_RETURN), r_inst,
rewriter_args->out_rtn = r_rtn; r_inst_cls);
rewriter_args->out_success = true; rewrite_args->setReturn(r_rtn, ReturnConvention::HAS_RETURN);
rewriter_args->out_return_convention = GetattrRewriteArgs::VALID_RETURN;
} }
return rtn; return rtn;
} }
if (rewrite_args)
grewriter_inst_args.assertReturnConvention(ReturnConvention::NO_RETURN);
return NULL; return NULL;
} }
static Box* instanceGetattributeWithFallback(BoxedInstance* inst, BoxedString* attr_str, static Box* instanceGetattributeWithFallback(BoxedInstance* inst, BoxedString* attr_str,
GetattrRewriteArgs* rewriter_args = NULL) { GetattrRewriteArgs* rewrite_args = NULL) {
Box* attr_obj = instanceGetattributeSimple(inst, attr_str, rewriter_args); Box* attr_obj = instanceGetattributeSimple(inst, attr_str, rewrite_args);
if (attr_obj) { if (attr_obj) {
if (rewrite_args && rewrite_args->isSuccessful())
rewrite_args->assertReturnConvention(
ReturnConvention::HAS_RETURN); // otherwise need to guard on the success
return attr_obj; return attr_obj;
} }
if (rewriter_args) { if (rewrite_args) {
if (!rewriter_args->out_success) if (!rewrite_args->isSuccessful())
rewriter_args = NULL; rewrite_args = NULL;
else else {
rewriter_args->out_success = false; rewrite_args->assertReturnConvention(ReturnConvention::NO_RETURN);
rewrite_args->clearReturn();
}
// abort rewriting for now // abort rewriting for now
rewriter_args = NULL; rewrite_args = NULL;
} }
static BoxedString* getattr_str = internStringImmortal("__getattr__"); static BoxedString* getattr_str = internStringImmortal("__getattr__");
...@@ -392,7 +406,7 @@ static Box* instanceGetattributeWithFallback(BoxedInstance* inst, BoxedString* a ...@@ -392,7 +406,7 @@ static Box* instanceGetattributeWithFallback(BoxedInstance* inst, BoxedString* a
} }
static Box* _instanceGetattribute(Box* _inst, BoxedString* attr_str, bool raise_on_missing, static Box* _instanceGetattribute(Box* _inst, BoxedString* attr_str, bool raise_on_missing,
GetattrRewriteArgs* rewriter_args = NULL) { GetattrRewriteArgs* rewrite_args = NULL) {
RELEASE_ASSERT(_inst->cls == instance_cls, ""); RELEASE_ASSERT(_inst->cls == instance_cls, "");
BoxedInstance* inst = static_cast<BoxedInstance*>(_inst); BoxedInstance* inst = static_cast<BoxedInstance*>(_inst);
...@@ -405,7 +419,7 @@ static Box* _instanceGetattribute(Box* _inst, BoxedString* attr_str, bool raise_ ...@@ -405,7 +419,7 @@ static Box* _instanceGetattribute(Box* _inst, BoxedString* attr_str, bool raise_
return inst->inst_cls; return inst->inst_cls;
} }
Box* attr = instanceGetattributeWithFallback(inst, attr_str, rewriter_args); Box* attr = instanceGetattributeWithFallback(inst, attr_str, rewrite_args);
if (attr) { if (attr) {
return attr; return attr;
} else if (!raise_on_missing) { } else if (!raise_on_missing) {
......
...@@ -92,6 +92,7 @@ static thread_local Timer per_thread_cleanup_timer(-1); ...@@ -92,6 +92,7 @@ static thread_local Timer per_thread_cleanup_timer(-1);
#ifndef NDEBUG #ifndef NDEBUG
static __thread bool in_cleanup_code = false; static __thread bool in_cleanup_code = false;
#endif #endif
static __thread bool is_unwinding = false;
extern "C" { extern "C" {
...@@ -567,6 +568,7 @@ static inline void unwind_loop(ExcInfo* exc_data) { ...@@ -567,6 +568,7 @@ static inline void unwind_loop(ExcInfo* exc_data) {
#if STAT_TIMERS #if STAT_TIMERS
pyston::StatTimer::finishOverride(); pyston::StatTimer::finishOverride();
#endif #endif
pyston::is_unwinding = false;
} }
static_assert(THREADING_USE_GIL, "have to make the unwind session usage in this file thread safe!"); static_assert(THREADING_USE_GIL, "have to make the unwind session usage in this file thread safe!");
// there is a python unwinding implementation detail leaked // there is a python unwinding implementation detail leaked
...@@ -610,6 +612,10 @@ void std::terminate() noexcept { ...@@ -610,6 +612,10 @@ void std::terminate() noexcept {
RELEASE_ASSERT(0, "std::terminate() called!"); RELEASE_ASSERT(0, "std::terminate() called!");
} }
bool std::uncaught_exception() noexcept {
return pyston::is_unwinding;
}
// wrong type signature, but that's okay, it's extern "C" // wrong type signature, but that's okay, it's extern "C"
extern "C" void __gxx_personality_v0() { extern "C" void __gxx_personality_v0() {
RELEASE_ASSERT(0, "__gxx_personality_v0 should never get called"); RELEASE_ASSERT(0, "__gxx_personality_v0 should never get called");
...@@ -684,9 +690,13 @@ extern "C" void __cxa_throw(void* exc_obj, std::type_info* tinfo, void (*dtor)(v ...@@ -684,9 +690,13 @@ extern "C" void __cxa_throw(void* exc_obj, std::type_info* tinfo, void (*dtor)(v
pyston::ExcInfo* exc_data = (pyston::ExcInfo*)exc_obj; pyston::ExcInfo* exc_data = (pyston::ExcInfo*)exc_obj;
checkExcInfo(exc_data); checkExcInfo(exc_data);
ASSERT(!pyston::is_unwinding, "We don't support throwing exceptions in destructors!");
pyston::is_unwinding = true;
#if STAT_TIMERS #if STAT_TIMERS
pyston::StatTimer::overrideCounter(unwinding_stattimer); pyston::StatTimer::overrideCounter(unwinding_stattimer);
#endif #endif
// let unwinding.cpp know we've started unwinding // let unwinding.cpp know we've started unwinding
pyston::logException(exc_data); pyston::logException(exc_data);
pyston::unwind(exc_data); pyston::unwind(exc_data);
......
...@@ -99,22 +99,22 @@ bool checkInst(LookupScope scope) { ...@@ -99,22 +99,22 @@ bool checkInst(LookupScope scope) {
} }
template <ExceptionStyle S> template <ExceptionStyle S>
static inline Box* callattrInternal0(Box* obj, BoxedString* attr, LookupScope scope, CallRewriteArgs* rewrite_args, static inline Box* callattrInternal0(Box* obj, BoxedString* attr, LookupScope scope, CallattrRewriteArgs* rewrite_args,
ArgPassSpec argspec) noexcept(S == CAPI) { ArgPassSpec argspec) noexcept(S == CAPI) {
return callattrInternal<S>(obj, attr, scope, rewrite_args, argspec, NULL, NULL, NULL, NULL, NULL); return callattrInternal<S>(obj, attr, scope, rewrite_args, argspec, NULL, NULL, NULL, NULL, NULL);
} }
template <ExceptionStyle S> template <ExceptionStyle S>
static inline Box* callattrInternal1(Box* obj, BoxedString* attr, LookupScope scope, CallRewriteArgs* rewrite_args, static inline Box* callattrInternal1(Box* obj, BoxedString* attr, LookupScope scope, CallattrRewriteArgs* rewrite_args,
ArgPassSpec argspec, Box* arg1) noexcept(S == CAPI) { ArgPassSpec argspec, Box* arg1) noexcept(S == CAPI) {
return callattrInternal<S>(obj, attr, scope, rewrite_args, argspec, arg1, NULL, NULL, NULL, NULL); return callattrInternal<S>(obj, attr, scope, rewrite_args, argspec, arg1, NULL, NULL, NULL, NULL);
} }
template <ExceptionStyle S> template <ExceptionStyle S>
static inline Box* callattrInternal2(Box* obj, BoxedString* attr, LookupScope scope, CallRewriteArgs* rewrite_args, static inline Box* callattrInternal2(Box* obj, BoxedString* attr, LookupScope scope, CallattrRewriteArgs* rewrite_args,
ArgPassSpec argspec, Box* arg1, Box* arg2) noexcept(S == CAPI) { ArgPassSpec argspec, Box* arg1, Box* arg2) noexcept(S == CAPI) {
return callattrInternal<S>(obj, attr, scope, rewrite_args, argspec, arg1, arg2, NULL, NULL, NULL); return callattrInternal<S>(obj, attr, scope, rewrite_args, argspec, arg1, arg2, NULL, NULL, NULL);
} }
template <ExceptionStyle S> template <ExceptionStyle S>
static inline Box* callattrInternal3(Box* obj, BoxedString* attr, LookupScope scope, CallRewriteArgs* rewrite_args, static inline Box* callattrInternal3(Box* obj, BoxedString* attr, LookupScope scope, CallattrRewriteArgs* rewrite_args,
ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3) noexcept(S == CAPI) { ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3) noexcept(S == CAPI) {
return callattrInternal<S>(obj, attr, scope, rewrite_args, argspec, arg1, arg2, arg3, NULL, NULL); return callattrInternal<S>(obj, attr, scope, rewrite_args, argspec, arg1, arg2, arg3, NULL, NULL);
} }
...@@ -739,7 +739,7 @@ Box* Box::getattr(BoxedString* attr, GetattrRewriteArgs* rewrite_args) { ...@@ -739,7 +739,7 @@ Box* Box::getattr(BoxedString* attr, GetattrRewriteArgs* rewrite_args) {
if (unlikely(hcls->type == HiddenClass::DICT_BACKED)) { if (unlikely(hcls->type == HiddenClass::DICT_BACKED)) {
if (rewrite_args) if (rewrite_args)
assert(!rewrite_args->out_success); assert(!rewrite_args->isSuccessful());
rewrite_args = NULL; rewrite_args = NULL;
Box* d = attrs->attr_list->attrs[0]; Box* d = attrs->attr_list->attrs[0];
assert(d); assert(d);
...@@ -769,10 +769,8 @@ Box* Box::getattr(BoxedString* attr, GetattrRewriteArgs* rewrite_args) { ...@@ -769,10 +769,8 @@ Box* Box::getattr(BoxedString* attr, GetattrRewriteArgs* rewrite_args) {
int offset = hcls->getOffset(attr); int offset = hcls->getOffset(attr);
if (offset == -1) { if (offset == -1) {
if (rewrite_args) { if (rewrite_args)
rewrite_args->out_success = true; rewrite_args->setReturn(NULL, ReturnConvention::NO_RETURN);
rewrite_args->out_return_convention = GetattrRewriteArgs::NO_RETURN;
}
return NULL; return NULL;
} }
...@@ -783,17 +781,12 @@ Box* Box::getattr(BoxedString* attr, GetattrRewriteArgs* rewrite_args) { ...@@ -783,17 +781,12 @@ Box* Box::getattr(BoxedString* attr, GetattrRewriteArgs* rewrite_args) {
} else { } else {
RewriterVar* r_attrs RewriterVar* r_attrs
= rewrite_args->obj->getAttr(cls->attrs_offset + offsetof(HCAttrs, attr_list), Location::any()); = rewrite_args->obj->getAttr(cls->attrs_offset + offsetof(HCAttrs, attr_list), Location::any());
rewrite_args->out_rtn RewriterVar* r_rtn
= r_attrs->getAttr(offset * sizeof(Box*) + offsetof(HCAttrs::AttrList, attrs), Location::any()); = r_attrs->getAttr(offset * sizeof(Box*) + offsetof(HCAttrs::AttrList, attrs), Location::any());
rewrite_args->setReturn(r_rtn, ReturnConvention::HAS_RETURN);
} }
} }
if (rewrite_args) {
rewrite_args->out_success = true;
assert(rewrite_args->out_rtn);
rewrite_args->out_return_convention = GetattrRewriteArgs::VALID_RETURN;
}
Box* rtn = attrs->attr_list->attrs[offset]; Box* rtn = attrs->attr_list->attrs[offset];
return rtn; return rtn;
} }
...@@ -811,11 +804,8 @@ Box* Box::getattr(BoxedString* attr, GetattrRewriteArgs* rewrite_args) { ...@@ -811,11 +804,8 @@ Box* Box::getattr(BoxedString* attr, GetattrRewriteArgs* rewrite_args) {
return it->second; return it->second;
} }
if (rewrite_args) { if (rewrite_args)
rewrite_args->out_success = true; rewrite_args->setReturn(NULL, ReturnConvention::NO_RETURN);
assert(rewrite_args->out_rtn == NULL);
rewrite_args->out_return_convention = GetattrRewriteArgs::NO_RETURN;
}
return NULL; return NULL;
} }
...@@ -991,7 +981,7 @@ Box* typeLookup(BoxedClass* cls, BoxedString* attr, GetattrRewriteArgs* rewrite_ ...@@ -991,7 +981,7 @@ Box* typeLookup(BoxedClass* cls, BoxedString* attr, GetattrRewriteArgs* rewrite_
Box* val; Box* val;
if (rewrite_args) { if (rewrite_args) {
assert(!rewrite_args->out_success); assert(!rewrite_args->isSuccessful());
RewriterVar* obj_saved = rewrite_args->obj; RewriterVar* obj_saved = rewrite_args->obj;
...@@ -1011,7 +1001,6 @@ Box* typeLookup(BoxedClass* cls, BoxedString* attr, GetattrRewriteArgs* rewrite_ ...@@ -1011,7 +1001,6 @@ Box* typeLookup(BoxedClass* cls, BoxedString* attr, GetattrRewriteArgs* rewrite_
for (auto base : *mro) { for (auto base : *mro) {
if (rewrite_args) { if (rewrite_args) {
rewrite_args->out_success = false;
if (base == cls) { if (base == cls) {
// Small optimization: don't have to load the class again since it was given to us in // Small optimization: don't have to load the class again since it was given to us in
// a register. // a register.
...@@ -1025,18 +1014,20 @@ Box* typeLookup(BoxedClass* cls, BoxedString* attr, GetattrRewriteArgs* rewrite_ ...@@ -1025,18 +1014,20 @@ Box* typeLookup(BoxedClass* cls, BoxedString* attr, GetattrRewriteArgs* rewrite_
} }
val = base->getattr(attr, rewrite_args); val = base->getattr(attr, rewrite_args);
if (rewrite_args && !rewrite_args->out_success) if (rewrite_args && !rewrite_args->isSuccessful())
rewrite_args = NULL; rewrite_args = NULL;
if (val) if (val)
return val; return val;
}
if (rewrite_args) { if (rewrite_args) {
assert(rewrite_args->out_success); rewrite_args->assertReturnConvention(ReturnConvention::NO_RETURN);
assert(!rewrite_args->out_rtn); rewrite_args->clearReturn();
rewrite_args->out_return_convention = GetattrRewriteArgs::NO_RETURN; }
} }
if (rewrite_args)
rewrite_args->setReturn(NULL, ReturnConvention::NO_RETURN);
return NULL; return NULL;
} else { } else {
assert(attr->interned_state != SSTATE_NOT_INTERNED); assert(attr->interned_state != SSTATE_NOT_INTERNED);
...@@ -1135,18 +1126,15 @@ Box* nondataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, Box ...@@ -1135,18 +1126,15 @@ Box* nondataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, Box
if (!for_call) { if (!for_call) {
if (rewrite_args) { if (rewrite_args) {
rewrite_args->out_rtn RewriterVar* r_rtn
= rewrite_args->rewriter->call(false, (void*)boxInstanceMethod, r_im_self, r_im_func, r_im_class); = rewrite_args->rewriter->call(false, (void*)boxInstanceMethod, r_im_self, r_im_func, r_im_class);
rewrite_args->out_success = true; rewrite_args->setReturn(r_rtn, ReturnConvention::HAS_RETURN);
rewrite_args->out_return_convention = GetattrRewriteArgs::VALID_RETURN;
} }
return boxInstanceMethod(im_self, im_func, im_class); return boxInstanceMethod(im_self, im_func, im_class);
} else { } else {
*bind_obj_out = im_self; *bind_obj_out = im_self;
if (rewrite_args) { if (rewrite_args) {
rewrite_args->out_rtn = r_im_func; rewrite_args->setReturn(r_im_func, ReturnConvention::HAS_RETURN);
rewrite_args->out_success = true;
rewrite_args->out_return_convention = GetattrRewriteArgs::VALID_RETURN;
*r_bind_obj_out = r_im_self; *r_bind_obj_out = r_im_self;
} }
return im_func; return im_func;
...@@ -1160,18 +1148,14 @@ Box* nondataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, Box ...@@ -1160,18 +1148,14 @@ Box* nondataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, Box
if (rewrite_args) { if (rewrite_args) {
RewriterVar* r_sm_callable = r_descr->getAttr(offsetof(BoxedStaticmethod, sm_callable)); RewriterVar* r_sm_callable = r_descr->getAttr(offsetof(BoxedStaticmethod, sm_callable));
r_sm_callable->addGuardNotEq(0); r_sm_callable->addGuardNotEq(0);
rewrite_args->out_success = true; rewrite_args->setReturn(r_sm_callable, ReturnConvention::HAS_RETURN);
rewrite_args->out_rtn = r_sm_callable;
rewrite_args->out_return_convention = GetattrRewriteArgs::VALID_RETURN;
} }
return sm->sm_callable; return sm->sm_callable;
} else if (descr->cls == wrapperdescr_cls) { } else if (descr->cls == wrapperdescr_cls) {
if (for_call) { if (for_call) {
if (rewrite_args) { if (rewrite_args) {
rewrite_args->out_success = true; rewrite_args->setReturn(r_descr, ReturnConvention::HAS_RETURN);
rewrite_args->out_rtn = r_descr;
rewrite_args->out_return_convention = GetattrRewriteArgs::VALID_RETURN;
*r_bind_obj_out = rewrite_args->obj; *r_bind_obj_out = rewrite_args->obj;
} }
*bind_obj_out = obj; *bind_obj_out = obj;
...@@ -1188,9 +1172,7 @@ Box* nondataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, Box ...@@ -1188,9 +1172,7 @@ Box* nondataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, Box
/* has_side_effects= */ false, (void*)&BoxedWrapperDescriptor::descr_get, r_descr, /* has_side_effects= */ false, (void*)&BoxedWrapperDescriptor::descr_get, r_descr,
rewrite_args->obj, r_descr->getAttr(offsetof(Box, cls), Location::forArg(2))); rewrite_args->obj, r_descr->getAttr(offsetof(Box, cls), Location::forArg(2)));
rewrite_args->out_success = true; rewrite_args->setReturn(r_rtn, ReturnConvention::CAPI_RETURN);
rewrite_args->out_rtn = r_rtn;
rewrite_args->out_return_convention = GetattrRewriteArgs::VALID_RETURN;
} }
return r; return r;
} }
...@@ -1199,6 +1181,7 @@ Box* nondataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, Box ...@@ -1199,6 +1181,7 @@ Box* nondataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, Box
return NULL; return NULL;
} }
// r_descr must represent a valid object.
Box* descriptorClsSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedClass* cls, Box* descr, RewriterVar* r_descr, Box* descriptorClsSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedClass* cls, Box* descr, RewriterVar* r_descr,
bool for_call, Box** bind_obj_out, RewriterVar** r_bind_obj_out) { bool for_call, Box** bind_obj_out, RewriterVar** r_bind_obj_out) {
// Special case: functions // Special case: functions
...@@ -1210,18 +1193,16 @@ Box* descriptorClsSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedClass* cls ...@@ -1210,18 +1193,16 @@ Box* descriptorClsSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedClass* cls
if (rewrite_args) { if (rewrite_args) {
// return an unbound instancemethod // return an unbound instancemethod
RewriterVar* r_cls = rewrite_args->obj; RewriterVar* r_cls = rewrite_args->obj;
rewrite_args->out_rtn RewriterVar* r_rtn
= rewrite_args->rewriter->call(true, (void*)boxUnboundInstanceMethod, r_descr, r_cls); = rewrite_args->rewriter->call(true, (void*)boxUnboundInstanceMethod, r_descr, r_cls);
rewrite_args->out_success = true; rewrite_args->setReturn(r_rtn, ReturnConvention::HAS_RETURN);
rewrite_args->out_return_convention = GetattrRewriteArgs::VALID_RETURN;
} }
return boxUnboundInstanceMethod(descr, cls); return boxUnboundInstanceMethod(descr, cls);
} }
if (rewrite_args) { if (rewrite_args) {
rewrite_args->out_success = true; // This is assuming that r_descr was passed in as a valid object
rewrite_args->out_rtn = r_descr; rewrite_args->setReturn(r_descr, ReturnConvention::HAS_RETURN);
rewrite_args->out_return_convention = GetattrRewriteArgs::VALID_RETURN;
} }
return descr; return descr;
} }
...@@ -1233,9 +1214,8 @@ Box* descriptorClsSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedClass* cls ...@@ -1233,9 +1214,8 @@ Box* descriptorClsSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedClass* cls
r_descr->addAttrGuard(offsetof(Box, cls), (uint64_t)descr->cls); r_descr->addAttrGuard(offsetof(Box, cls), (uint64_t)descr->cls);
if (rewrite_args) { if (rewrite_args) {
rewrite_args->out_rtn = r_descr; // This is assuming that r_descr was passed in as a valid object
rewrite_args->out_success = true; rewrite_args->setReturn(r_descr, ReturnConvention::HAS_RETURN);
rewrite_args->out_return_convention = GetattrRewriteArgs::VALID_RETURN;
} }
return descr; return descr;
} }
...@@ -1249,6 +1229,7 @@ Box* boxChar(char c) { ...@@ -1249,6 +1229,7 @@ Box* boxChar(char c) {
return boxString(llvm::StringRef(d, 1)); return boxString(llvm::StringRef(d, 1));
} }
// r_descr needs to represent a valid object
Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedString* attr_name, Box* obj, Box* descr, Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedString* attr_name, Box* obj, Box* descr,
RewriterVar* r_descr, bool for_call, Box** bind_obj_out, RewriterVar* r_descr, bool for_call, Box** bind_obj_out,
RewriterVar** r_bind_obj_out) { RewriterVar** r_bind_obj_out) {
...@@ -1277,10 +1258,9 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS ...@@ -1277,10 +1258,9 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS
switch (member_desc->type) { switch (member_desc->type) {
case BoxedMemberDescriptor::OBJECT_EX: { case BoxedMemberDescriptor::OBJECT_EX: {
if (rewrite_args) { if (rewrite_args) {
rewrite_args->out_rtn = rewrite_args->obj->getAttr(member_desc->offset, rewrite_args->destination); RewriterVar* r_rtn = rewrite_args->obj->getAttr(member_desc->offset, rewrite_args->destination);
rewrite_args->out_rtn->addGuardNotEq(0); r_rtn->addGuardNotEq(0);
rewrite_args->out_success = true; rewrite_args->setReturn(r_rtn, ReturnConvention::HAS_RETURN);
rewrite_args->out_return_convention = GetattrRewriteArgs::VALID_RETURN;
} }
Box* rtn = *reinterpret_cast<Box**>((char*)obj + member_desc->offset); Box* rtn = *reinterpret_cast<Box**>((char*)obj + member_desc->offset);
...@@ -1294,9 +1274,8 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS ...@@ -1294,9 +1274,8 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS
if (rewrite_args) { if (rewrite_args) {
RewriterVar* r_interm = rewrite_args->obj->getAttr(member_desc->offset, rewrite_args->destination); RewriterVar* r_interm = rewrite_args->obj->getAttr(member_desc->offset, rewrite_args->destination);
// TODO would be faster to not use a call // TODO would be faster to not use a call
rewrite_args->out_rtn = rewrite_args->rewriter->call(false, (void*)noneIfNull, r_interm); RewriterVar* r_rtn = rewrite_args->rewriter->call(false, (void*)noneIfNull, r_interm);
rewrite_args->out_success = true; rewrite_args->setReturn(r_rtn, ReturnConvention::HAS_RETURN);
rewrite_args->out_return_convention = GetattrRewriteArgs::VALID_RETURN;
} }
Box* rtn = *reinterpret_cast<Box**>((char*)obj + member_desc->offset); Box* rtn = *reinterpret_cast<Box**>((char*)obj + member_desc->offset);
...@@ -1309,10 +1288,8 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS ...@@ -1309,10 +1288,8 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS
RewriterVar::SmallVector normal_args; RewriterVar::SmallVector normal_args;
RewriterVar::SmallVector float_args; RewriterVar::SmallVector float_args;
float_args.push_back(r_unboxed_val); float_args.push_back(r_unboxed_val);
rewrite_args->out_rtn RewriterVar* r_rtn = rewrite_args->rewriter->call(false, (void*)boxFloat, normal_args, float_args);
= rewrite_args->rewriter->call(false, (void*)boxFloat, normal_args, float_args); rewrite_args->setReturn(r_rtn, ReturnConvention::HAS_RETURN);
rewrite_args->out_success = true;
rewrite_args->out_return_convention = GetattrRewriteArgs::VALID_RETURN;
} }
double rtn = *reinterpret_cast<double*>((char*)obj + member_desc->offset); double rtn = *reinterpret_cast<double*>((char*)obj + member_desc->offset);
...@@ -1324,10 +1301,8 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS ...@@ -1324,10 +1301,8 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS
RewriterVar::SmallVector normal_args; RewriterVar::SmallVector normal_args;
RewriterVar::SmallVector float_args; RewriterVar::SmallVector float_args;
float_args.push_back(r_unboxed_val); float_args.push_back(r_unboxed_val);
rewrite_args->out_rtn RewriterVar* r_rtn = rewrite_args->rewriter->call(true, (void*)boxFloat, normal_args, float_args);
= rewrite_args->rewriter->call(true, (void*)boxFloat, normal_args, float_args); rewrite_args->setReturn(r_rtn, ReturnConvention::HAS_RETURN);
rewrite_args->out_success = true;
rewrite_args->out_return_convention = GetattrRewriteArgs::VALID_RETURN;
} }
float rtn = *reinterpret_cast<float*>((char*)obj + member_desc->offset); float rtn = *reinterpret_cast<float*>((char*)obj + member_desc->offset);
...@@ -1338,9 +1313,9 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS ...@@ -1338,9 +1313,9 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS
case BoxedMemberDescriptor::TYPE: { \ case BoxedMemberDescriptor::TYPE: { \
if (rewrite_args) { \ if (rewrite_args) { \
RewriterVar* r_unboxed_val = rewrite_args->obj->getAttrCast<type, cast>(member_desc->offset); \ RewriterVar* r_unboxed_val = rewrite_args->obj->getAttrCast<type, cast>(member_desc->offset); \
rewrite_args->out_rtn = rewrite_args->rewriter->call(true, (void*)boxFn, r_unboxed_val); \ RewriterVar* r_rtn = rewrite_args->rewriter->call(true, (void*)boxFn, r_unboxed_val); \
rewrite_args->out_success = true; \ /* XXX assuming that none of these throw a capi error! */ \
rewrite_args->out_return_convention = GetattrRewriteArgs::VALID_RETURN; \ rewrite_args->setReturn(r_rtn, ReturnConvention::HAS_RETURN); \
} \ } \
type rtn = *reinterpret_cast<type*>((char*)obj + member_desc->offset); \ type rtn = *reinterpret_cast<type*>((char*)obj + member_desc->offset); \
return boxFn((cast)rtn); \ return boxFn((cast)rtn); \
...@@ -1362,9 +1337,8 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS ...@@ -1362,9 +1337,8 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS
case BoxedMemberDescriptor::STRING: { case BoxedMemberDescriptor::STRING: {
if (rewrite_args) { if (rewrite_args) {
RewriterVar* r_interm = rewrite_args->obj->getAttr(member_desc->offset, rewrite_args->destination); RewriterVar* r_interm = rewrite_args->obj->getAttr(member_desc->offset, rewrite_args->destination);
rewrite_args->out_rtn = rewrite_args->rewriter->call(true, (void*)boxStringOrNone, r_interm); RewriterVar* r_rtn = rewrite_args->rewriter->call(true, (void*)boxStringOrNone, r_interm);
rewrite_args->out_success = true; rewrite_args->setReturn(r_rtn, ReturnConvention::HAS_RETURN);
rewrite_args->out_return_convention = GetattrRewriteArgs::VALID_RETURN;
} }
char* rtn = *reinterpret_cast<char**>((char*)obj + member_desc->offset); char* rtn = *reinterpret_cast<char**>((char*)obj + member_desc->offset);
...@@ -1372,11 +1346,10 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS ...@@ -1372,11 +1346,10 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS
} }
case BoxedMemberDescriptor::STRING_INPLACE: { case BoxedMemberDescriptor::STRING_INPLACE: {
if (rewrite_args) { if (rewrite_args) {
rewrite_args->out_rtn = rewrite_args->rewriter->call( RewriterVar* r_rtn = rewrite_args->rewriter->call(
true, (void*)boxStringFromCharPtr, true, (void*)boxStringFromCharPtr,
rewrite_args->rewriter->add(rewrite_args->obj, member_desc->offset, rewrite_args->destination)); rewrite_args->rewriter->add(rewrite_args->obj, member_desc->offset, rewrite_args->destination));
rewrite_args->out_success = true; rewrite_args->setReturn(r_rtn, ReturnConvention::HAS_RETURN);
rewrite_args->out_return_convention = GetattrRewriteArgs::VALID_RETURN;
} }
rewrite_args = NULL; rewrite_args = NULL;
...@@ -1407,9 +1380,7 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS ...@@ -1407,9 +1380,7 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS
if (!crewrite_args.out_success) { if (!crewrite_args.out_success) {
rewrite_args = NULL; rewrite_args = NULL;
} else { } else {
rewrite_args->out_success = true; rewrite_args->setReturn(crewrite_args.out_rtn, ReturnConvention::HAS_RETURN);
rewrite_args->out_rtn = crewrite_args.out_rtn;
rewrite_args->out_return_convention = GetattrRewriteArgs::VALID_RETURN;
} }
return rtn; return rtn;
} }
...@@ -1442,14 +1413,11 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS ...@@ -1442,14 +1413,11 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS
r_descr->addAttrGuard(offsetof(BoxedGetsetDescriptor, get), (intptr_t)getset_descr->get); r_descr->addAttrGuard(offsetof(BoxedGetsetDescriptor, get), (intptr_t)getset_descr->get);
RewriterVar* r_closure = r_descr->getAttr(offsetof(BoxedGetsetDescriptor, closure)); RewriterVar* r_closure = r_descr->getAttr(offsetof(BoxedGetsetDescriptor, closure));
rewrite_args->out_rtn = rewrite_args->rewriter->call( RewriterVar* r_rtn = rewrite_args->rewriter->call(
/* has_side_effects */ true, (void*)getset_descr->get, rewrite_args->obj, r_closure); /* has_side_effects */ true, (void*)getset_descr->get, rewrite_args->obj, r_closure);
if (descr->cls == capi_getset_cls) rewrite_args->setReturn(r_rtn, descr->cls == capi_getset_cls ? ReturnConvention::CAPI_RETURN
rewrite_args->rewriter->checkAndThrowCAPIException(rewrite_args->out_rtn); : ReturnConvention::HAS_RETURN);
rewrite_args->out_success = true;
rewrite_args->out_return_convention = GetattrRewriteArgs::VALID_RETURN;
} }
return getset_descr->get(obj, getset_descr->closure); return getset_descr->get(obj, getset_descr->closure);
...@@ -1511,14 +1479,8 @@ Box* getattrInternalEx(Box* obj, BoxedString* attr, GetattrRewriteArgs* rewrite_ ...@@ -1511,14 +1479,8 @@ Box* getattrInternalEx(Box* obj, BoxedString* attr, GetattrRewriteArgs* rewrite_
auto r_box = rewrite_args->rewriter->loadConst((intptr_t)attr); 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); auto r_rtn = rewrite_args->rewriter->call(true, (void*)obj->cls->tp_getattro, rewrite_args->obj, r_box);
if (S == CXX) rewrite_args->rewriter->call(false, (void*)ensureValidCapiReturn, r_rtn);
rewrite_args->rewriter->checkAndThrowCAPIException(r_rtn); rewrite_args->setReturn(r_rtn, ReturnConvention::CAPI_RETURN);
else
rewrite_args->rewriter->call(false, (void*)ensureValidCapiReturn, r_rtn);
rewrite_args->out_rtn = r_rtn;
rewrite_args->out_success = true;
rewrite_args->out_return_convention = GetattrRewriteArgs::VALID_RETURN;
} }
if (!r) { if (!r) {
...@@ -1577,12 +1539,11 @@ Box* getattrInternalEx(Box* obj, BoxedString* attr, GetattrRewriteArgs* rewrite_ ...@@ -1577,12 +1539,11 @@ Box* getattrInternalEx(Box* obj, BoxedString* attr, GetattrRewriteArgs* rewrite_
} }
}; };
rewrite_args->out_rtn RewriterVar* r_rtn
= rewrite_args->rewriter->call(true, (void*)Helper::call, rewrite_args->obj, = rewrite_args->rewriter->call(true, (void*)Helper::call, rewrite_args->obj,
rewrite_args->rewriter->loadConst((intptr_t)attr, Location::forArg(1)), rewrite_args->rewriter->loadConst((intptr_t)attr, Location::forArg(1)),
rewrite_args->rewriter->loadConst(cls_only, Location::forArg(2))); rewrite_args->rewriter->loadConst(cls_only, Location::forArg(2)));
rewrite_args->out_success = true; rewrite_args->setReturn(r_rtn, ReturnConvention::NOEXC_POSSIBLE);
rewrite_args->out_return_convention = GetattrRewriteArgs::NOEXC_POSSIBLE;
return Helper::call(obj, attr, cls_only); return Helper::call(obj, attr, cls_only);
} }
...@@ -1633,9 +1594,9 @@ extern "C" Box* getclsattr(Box* obj, BoxedString* attr) { ...@@ -1633,9 +1594,9 @@ extern "C" Box* getclsattr(Box* obj, BoxedString* attr) {
GetattrRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0), rewriter->getReturnDestination()); GetattrRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0), rewriter->getReturnDestination());
gotten = getclsattrInternal(obj, attr, &rewrite_args); gotten = getclsattrInternal(obj, attr, &rewrite_args);
if (rewrite_args.out_success && gotten) { if (rewrite_args.isSuccessful() && gotten) {
assert(rewrite_args.out_return_convention == GetattrRewriteArgs::VALID_RETURN); RewriterVar* r_rtn = rewrite_args.getReturn(ReturnConvention::HAS_RETURN);
rewriter->commitReturning(rewrite_args.out_rtn); rewriter->commitReturning(r_rtn);
} }
#endif #endif
} }
...@@ -1714,13 +1675,12 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew ...@@ -1714,13 +1675,12 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew
GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, r_obj_cls, rewrite_args->destination); GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, r_obj_cls, rewrite_args->destination);
descr = typeLookup(obj->cls, attr, &grewrite_args); descr = typeLookup(obj->cls, attr, &grewrite_args);
if (!grewrite_args.out_success) { if (!grewrite_args.isSuccessful()) {
rewrite_args = NULL; rewrite_args = NULL;
} else if (descr) { } else if (descr) {
assert(grewrite_args.out_return_convention == GetattrRewriteArgs::VALID_RETURN); r_descr = grewrite_args.getReturn(ReturnConvention::HAS_RETURN);
r_descr = grewrite_args.out_rtn;
} else { } else {
assert(grewrite_args.out_return_convention == GetattrRewriteArgs::NO_RETURN); grewrite_args.assertReturnConvention(ReturnConvention::NO_RETURN);
} }
} else { } else {
descr = typeLookup(obj->cls, attr, NULL); descr = typeLookup(obj->cls, attr, NULL);
...@@ -1762,11 +1722,10 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew ...@@ -1762,11 +1722,10 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew
GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, r_descr_cls, Location::any()); GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, r_descr_cls, Location::any());
_get_ = typeLookup(descr->cls, get_str, &grewrite_args); _get_ = typeLookup(descr->cls, get_str, &grewrite_args);
assert(_get_); assert(_get_);
if (!grewrite_args.out_success) { if (!grewrite_args.isSuccessful()) {
rewrite_args = NULL; rewrite_args = NULL;
} else if (_get_) { } else if (_get_) {
assert(grewrite_args.out_return_convention == GetattrRewriteArgs::VALID_RETURN); r_get = grewrite_args.getReturn(ReturnConvention::HAS_RETURN);
r_get = grewrite_args.out_rtn;
} }
} else { } else {
// Don't look up __get__ if we can't rewrite under the assumption that it will // Don't look up __get__ if we can't rewrite under the assumption that it will
...@@ -1786,11 +1745,11 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew ...@@ -1786,11 +1745,11 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew
RewriterVar* r_descr_cls = r_descr->getAttr(offsetof(Box, cls), Location::any()); RewriterVar* r_descr_cls = r_descr->getAttr(offsetof(Box, cls), Location::any());
GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, r_descr_cls, Location::any()); GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, r_descr_cls, Location::any());
_set_ = typeLookup(descr->cls, set_str, &grewrite_args); _set_ = typeLookup(descr->cls, set_str, &grewrite_args);
if (!grewrite_args.out_success) { if (!grewrite_args.isSuccessful()) {
rewrite_args = NULL; rewrite_args = NULL;
} else { } else {
assert(grewrite_args.out_return_convention grewrite_args.assertReturnConvention(_set_ ? ReturnConvention::HAS_RETURN
== (_set_ ? GetattrRewriteArgs::VALID_RETURN : GetattrRewriteArgs::NO_RETURN)); : ReturnConvention::NO_RETURN);
} }
} else { } else {
_set_ = typeLookup(descr->cls, set_str, NULL); _set_ = typeLookup(descr->cls, set_str, NULL);
...@@ -1824,9 +1783,7 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew ...@@ -1824,9 +1783,7 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew
if (!crewrite_args.out_success) { if (!crewrite_args.out_success) {
rewrite_args = NULL; rewrite_args = NULL;
} else { } else {
rewrite_args->out_success = true; rewrite_args->setReturn(crewrite_args.out_rtn, ReturnConvention::HAS_RETURN);
rewrite_args->out_rtn = crewrite_args.out_rtn;
rewrite_args->out_return_convention = GetattrRewriteArgs::VALID_RETURN;
} }
} else { } else {
res = descr_get(descr, obj, obj->cls); res = descr_get(descr, obj, obj->cls);
...@@ -1851,40 +1808,31 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew ...@@ -1851,40 +1808,31 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew
static Box* call(Box* obj, BoxedString* attr) { return obj->getattr(attr); } static Box* call(Box* obj, BoxedString* attr) { return obj->getattr(attr); }
}; };
rewrite_args->out_rtn = rewrite_args->rewriter->call( RewriterVar* r_rtn = rewrite_args->rewriter->call(
false, (void*)Helper::call, rewrite_args->obj, false, (void*)Helper::call, rewrite_args->obj,
rewrite_args->rewriter->loadConst((intptr_t)attr, Location::forArg(1))); rewrite_args->rewriter->loadConst((intptr_t)attr, Location::forArg(1)));
rewrite_args->out_success = true; rewrite_args->setReturn(r_rtn, ReturnConvention::NOEXC_POSSIBLE);
rewrite_args->out_return_convention = GetattrRewriteArgs::NOEXC_POSSIBLE;
return Helper::call(obj, attr); return Helper::call(obj, attr);
} }
Box* val; Box* val;
RewriterVar* r_val = NULL;
if (rewrite_args) { if (rewrite_args) {
GetattrRewriteArgs hrewrite_args(rewrite_args->rewriter, rewrite_args->obj, rewrite_args->destination); GetattrRewriteArgs hrewrite_args(rewrite_args->rewriter, rewrite_args->obj, rewrite_args->destination);
val = obj->getattr(attr, &hrewrite_args); val = obj->getattr(attr, &hrewrite_args);
if (!hrewrite_args.out_success) { if (!hrewrite_args.isSuccessful()) {
rewrite_args = NULL; rewrite_args = NULL;
} else if (val) { } else if (val) {
assert(hrewrite_args.out_return_convention == GetattrRewriteArgs::VALID_RETURN); rewrite_args->setReturn(hrewrite_args.getReturn());
r_val = hrewrite_args.out_rtn;
} else { } else {
assert(hrewrite_args.out_return_convention == GetattrRewriteArgs::NO_RETURN); hrewrite_args.assertReturnConvention(ReturnConvention::NO_RETURN);
} }
} else { } else {
val = obj->getattr(attr, NULL); val = obj->getattr(attr, NULL);
} }
if (val) { if (val)
if (rewrite_args) {
rewrite_args->out_rtn = r_val;
rewrite_args->out_success = true;
rewrite_args->out_return_convention = GetattrRewriteArgs::VALID_RETURN;
}
return val; return val;
}
} else { } else {
// More complicated when obj is a type // More complicated when obj is a type
// We have to look up the attr in the entire // We have to look up the attr in the entire
...@@ -1898,11 +1846,12 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew ...@@ -1898,11 +1846,12 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew
GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, rewrite_args->obj, rewrite_args->destination); GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, rewrite_args->obj, rewrite_args->destination);
val = typeLookup(static_cast<BoxedClass*>(obj), attr, &grewrite_args); val = typeLookup(static_cast<BoxedClass*>(obj), attr, &grewrite_args);
if (!grewrite_args.out_success) { if (!grewrite_args.isSuccessful()) {
rewrite_args = NULL; rewrite_args = NULL;
} else if (val) { } else if (val) {
assert(grewrite_args.out_return_convention == GetattrRewriteArgs::VALID_RETURN); r_val = grewrite_args.getReturn(ReturnConvention::HAS_RETURN);
r_val = grewrite_args.out_rtn; } else {
grewrite_args.assertReturnConvention(ReturnConvention::NO_RETURN);
} }
} else { } else {
val = typeLookup(static_cast<BoxedClass*>(obj), attr, NULL); val = typeLookup(static_cast<BoxedClass*>(obj), attr, NULL);
...@@ -1923,11 +1872,8 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew ...@@ -1923,11 +1872,8 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew
} }
if (!local_get) { if (!local_get) {
if (rewrite_args) { if (rewrite_args)
rewrite_args->out_rtn = r_val; rewrite_args->setReturn(r_val, ReturnConvention::HAS_RETURN);
rewrite_args->out_success = true;
rewrite_args->out_return_convention = GetattrRewriteArgs::VALID_RETURN;
}
return val; return val;
} }
...@@ -1937,12 +1883,11 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew ...@@ -1937,12 +1883,11 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew
throwCAPIException(); throwCAPIException();
if (rewrite_args) { if (rewrite_args) {
rewrite_args->out_rtn = rewrite_args->rewriter->call( RewriterVar* r_rtn = rewrite_args->rewriter->call(
true, (void*)local_get, r_val, rewrite_args->rewriter->loadConst(0, Location::forArg(1)), true, (void*)local_get, r_val, rewrite_args->rewriter->loadConst(0, Location::forArg(1)),
rewrite_args->obj); rewrite_args->obj);
rewrite_args->rewriter->checkAndThrowCAPIException(rewrite_args->out_rtn); // rewrite_args->rewriter->checkAndThrowCAPIException(rewrite_args->out_rtn);
rewrite_args->out_success = true; rewrite_args->setReturn(r_rtn, ReturnConvention::CAPI_RETURN);
rewrite_args->out_return_convention = GetattrRewriteArgs::VALID_RETURN;
} }
return r; return r;
...@@ -1987,9 +1932,7 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew ...@@ -1987,9 +1932,7 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew
if (!crewrite_args.out_success) { if (!crewrite_args.out_success) {
rewrite_args = NULL; rewrite_args = NULL;
} else { } else {
rewrite_args->out_success = true; rewrite_args->setReturn(crewrite_args.out_rtn, ReturnConvention::HAS_RETURN);
rewrite_args->out_rtn = crewrite_args.out_rtn;
rewrite_args->out_return_convention = GetattrRewriteArgs::VALID_RETURN;
} }
} else { } else {
res = descr_get(descr, obj, obj->cls); res = descr_get(descr, obj, obj->cls);
...@@ -2001,24 +1944,20 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew ...@@ -2001,24 +1944,20 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew
// Otherwise, just return descr. // Otherwise, just return descr.
if (rewrite_args) { if (rewrite_args) {
rewrite_args->out_rtn = r_descr; rewrite_args->setReturn(r_descr, ReturnConvention::HAS_RETURN);
rewrite_args->out_success = true;
rewrite_args->out_return_convention = GetattrRewriteArgs::VALID_RETURN;
} }
return descr; return descr;
} }
// TODO this shouldn't go here; it should be in instancemethod_cls->tp_getattr[o] // TODO this shouldn't go here; it should be in instancemethod_cls->tp_getattr[o]
if (obj->cls == instancemethod_cls) { if (obj->cls == instancemethod_cls) {
assert(!rewrite_args || !rewrite_args->out_success); assert(!rewrite_args || !rewrite_args->isSuccessful());
return getattrInternalEx<CXX>(static_cast<BoxedInstanceMethod*>(obj)->func, attr, NULL, cls_only, for_call, return getattrInternalEx<CXX>(static_cast<BoxedInstanceMethod*>(obj)->func, attr, NULL, cls_only, for_call,
bind_obj_out, NULL); bind_obj_out, NULL);
} }
if (rewrite_args) { if (rewrite_args)
rewrite_args->out_success = true; rewrite_args->setReturn(NULL, ReturnConvention::NO_RETURN);
rewrite_args->out_return_convention = GetattrRewriteArgs::NO_RETURN;
}
return NULL; return NULL;
} }
...@@ -2128,30 +2067,33 @@ template <ExceptionStyle S> Box* _getattrEntry(Box* obj, BoxedString* attr, void ...@@ -2128,30 +2067,33 @@ template <ExceptionStyle S> Box* _getattrEntry(Box* obj, BoxedString* attr, void
GetattrRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0), dest); GetattrRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0), dest);
val = getattrInternal<S>(obj, attr, &rewrite_args); val = getattrInternal<S>(obj, attr, &rewrite_args);
if (rewrite_args.out_success) { if (rewrite_args.isSuccessful()) {
assert(rewrite_args.out_return_convention != GetattrRewriteArgs::UNSPECIFIED); RewriterVar* rtn;
ReturnConvention return_convention;
std::tie(rtn, return_convention) = rewrite_args.getReturn();
if (rewrite_args.out_return_convention != GetattrRewriteArgs::VALID_RETURN) { // Try to munge the return into the right form:
if (return_convention != ReturnConvention::HAS_RETURN) {
if (attr->interned_state == SSTATE_INTERNED_IMMORTAL) { if (attr->interned_state == SSTATE_INTERNED_IMMORTAL) {
if (rewrite_args.out_return_convention == GetattrRewriteArgs::NO_RETURN) { if (return_convention == ReturnConvention::NO_RETURN) {
assert(!rewrite_args.out_rtn); assert(!rtn);
rewrite_args.out_rtn = rewriter->loadConst(0, Location::forArg(1)); rtn = rewriter->loadConst(0, Location::forArg(1));
} }
rewriter->call(true, (void*)NoexcHelper::call, rewrite_args.out_rtn, rewriter->getArg(0), rewriter->call(true, (void*)NoexcHelper::call, rtn, rewriter->getArg(0),
rewriter->loadConst((intptr_t)attr, Location::forArg(2))); rewriter->loadConst((intptr_t)attr, Location::forArg(2)));
rewrite_args.out_return_convention = GetattrRewriteArgs::VALID_RETURN; return_convention = (S == CXX) ? ReturnConvention::HAS_RETURN : ReturnConvention::CAPI_RETURN;
} }
} }
if (rewrite_args.out_return_convention == GetattrRewriteArgs::VALID_RETURN) { if (return_convention == ReturnConvention::HAS_RETURN
RewriterVar* r_rtn = rewrite_args.out_rtn; || (S == CAPI && return_convention == ReturnConvention::CAPI_RETURN)) {
if (recorder) { if (recorder) {
r_rtn = rewriter->call(false, (void*)recordType, rtn = rewriter->call(false, (void*)recordType,
rewriter->loadConst((intptr_t)recorder, Location::forArg(0)), r_rtn); rewriter->loadConst((intptr_t)recorder, Location::forArg(0)), rtn);
recordType(recorder, val); recordType(recorder, val);
} }
rewriter->commitReturning(r_rtn); rewriter->commitReturning(rtn);
} }
} }
} else { } else {
...@@ -2248,11 +2190,12 @@ void setattrGeneric(Box* obj, BoxedString* attr, Box* val, SetattrRewriteArgs* r ...@@ -2248,11 +2190,12 @@ void setattrGeneric(Box* obj, BoxedString* attr, Box* val, SetattrRewriteArgs* r
GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, r_cls, rewrite_args->rewriter->getReturnDestination()); GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, r_cls, rewrite_args->rewriter->getReturnDestination());
descr = typeLookup(obj->cls, attr, &grewrite_args); descr = typeLookup(obj->cls, attr, &grewrite_args);
if (!grewrite_args.out_success) { if (!grewrite_args.isSuccessful()) {
rewrite_args = NULL; rewrite_args = NULL;
} else if (descr) { } else if (descr) {
assert(grewrite_args.out_return_convention == GetattrRewriteArgs::VALID_RETURN); r_descr = grewrite_args.getReturn(ReturnConvention::HAS_RETURN);
r_descr = grewrite_args.out_rtn; } else {
grewrite_args.assertReturnConvention(ReturnConvention::NO_RETURN);
} }
} else { } else {
descr = typeLookup(obj->cls, attr, NULL); descr = typeLookup(obj->cls, attr, NULL);
...@@ -2271,11 +2214,12 @@ void setattrGeneric(Box* obj, BoxedString* attr, Box* val, SetattrRewriteArgs* r ...@@ -2271,11 +2214,12 @@ void setattrGeneric(Box* obj, BoxedString* attr, Box* val, SetattrRewriteArgs* r
RewriterVar* r_cls = r_descr->getAttr(offsetof(Box, cls), Location::any()); RewriterVar* r_cls = r_descr->getAttr(offsetof(Box, cls), Location::any());
GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, r_cls, Location::any()); GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, r_cls, Location::any());
_set_ = typeLookup(descr->cls, set_str, &grewrite_args); _set_ = typeLookup(descr->cls, set_str, &grewrite_args);
if (!grewrite_args.out_success) { if (!grewrite_args.isSuccessful()) {
rewrite_args = NULL; rewrite_args = NULL;
} else if (_set_) { } else if (_set_) {
assert(grewrite_args.out_return_convention == GetattrRewriteArgs::VALID_RETURN); r_set = grewrite_args.getReturn(ReturnConvention::HAS_RETURN);
r_set = grewrite_args.out_rtn; } else {
grewrite_args.assertReturnConvention(ReturnConvention::NO_RETURN);
} }
} else { } else {
_set_ = typeLookup(descr->cls, set_str, NULL); _set_ = typeLookup(descr->cls, set_str, NULL);
...@@ -2368,9 +2312,8 @@ extern "C" void setattr(Box* obj, BoxedString* attr, Box* attr_val) { ...@@ -2368,9 +2312,8 @@ extern "C" void setattr(Box* obj, BoxedString* attr, Box* attr_val) {
setattr = typeLookup(obj->cls, setattr_str, &rewrite_args); setattr = typeLookup(obj->cls, setattr_str, &rewrite_args);
assert(setattr); assert(setattr);
if (rewrite_args.out_success) { if (rewrite_args.isSuccessful()) {
r_setattr = rewrite_args.out_rtn; r_setattr = rewrite_args.getReturn(ReturnConvention::HAS_RETURN);
assert(rewrite_args.out_return_convention == GetattrRewriteArgs::VALID_RETURN);
// TODO this is not good enough, since the object could get collected: // TODO this is not good enough, since the object could get collected:
r_setattr->addGuard((intptr_t)setattr); r_setattr->addGuard((intptr_t)setattr);
} else { } else {
...@@ -2535,22 +2478,28 @@ extern "C" bool nonzero(Box* obj) { ...@@ -2535,22 +2478,28 @@ extern "C" bool nonzero(Box* obj) {
static BoxedString* len_str = internStringImmortal("__len__"); static BoxedString* len_str = internStringImmortal("__len__");
// try __nonzero__ // try __nonzero__
CallRewriteArgs crewrite_args(rewriter.get(), r_obj, CallattrRewriteArgs crewrite_args(rewriter.get(), r_obj,
rewriter.get() ? rewriter->getReturnDestination() : Location()); rewriter.get() ? rewriter->getReturnDestination() : Location());
Box* rtn Box* rtn
= callattrInternal0<CXX>(obj, nonzero_str, CLASS_ONLY, rewriter.get() ? &crewrite_args : NULL, ArgPassSpec(0)); = callattrInternal0<CXX>(obj, nonzero_str, CLASS_ONLY, rewriter.get() ? &crewrite_args : NULL, ArgPassSpec(0));
if (!crewrite_args.out_success) if (!crewrite_args.isSuccessful())
rewriter.reset(); rewriter.reset();
if (!rtn) { if (!rtn) {
if (rewriter.get())
crewrite_args.assertReturnConvention(ReturnConvention::NO_RETURN);
// try __len__ // try __len__
crewrite_args crewrite_args = CallattrRewriteArgs(rewriter.get(), r_obj,
= CallRewriteArgs(rewriter.get(), r_obj, rewriter.get() ? rewriter->getReturnDestination() : Location()); rewriter.get() ? rewriter->getReturnDestination() : Location());
rtn = callattrInternal0<CXX>(obj, len_str, CLASS_ONLY, rewriter.get() ? &crewrite_args : NULL, ArgPassSpec(0)); rtn = callattrInternal0<CXX>(obj, len_str, CLASS_ONLY, rewriter.get() ? &crewrite_args : NULL, ArgPassSpec(0));
if (!crewrite_args.out_success) if (!crewrite_args.isSuccessful())
rewriter.reset(); rewriter.reset();
if (rtn == NULL) { if (rtn == NULL) {
if (rewriter.get()) {
crewrite_args.assertReturnConvention(ReturnConvention::NO_RETURN);
}
ASSERT(obj->cls->is_user_defined || obj->cls->instances_are_nonzero || obj->cls == classobj_cls ASSERT(obj->cls->is_user_defined || obj->cls->instances_are_nonzero || obj->cls == classobj_cls
|| obj->cls == type_cls || isSubclass(obj->cls, Exception) || obj->cls == file_cls || obj->cls == type_cls || isSubclass(obj->cls, Exception) || obj->cls == file_cls
|| obj->cls == traceback_cls || obj->cls == instancemethod_cls || obj->cls == module_cls || obj->cls == traceback_cls || obj->cls == instancemethod_cls || obj->cls == module_cls
...@@ -2567,8 +2516,10 @@ extern "C" bool nonzero(Box* obj) { ...@@ -2567,8 +2516,10 @@ extern "C" bool nonzero(Box* obj) {
return true; return true;
} }
} }
if (crewrite_args.out_success) {
RewriterVar* b = rewriter->call(false, (void*)nonzeroHelper, crewrite_args.out_rtn); if (crewrite_args.isSuccessful()) {
RewriterVar* rtn = crewrite_args.getReturn(ReturnConvention::HAS_RETURN);
RewriterVar* b = rewriter->call(false, (void*)nonzeroHelper, rtn);
rewriter->commitReturning(b); rewriter->commitReturning(b);
} }
return nonzeroHelper(rtn); return nonzeroHelper(rtn);
...@@ -2742,12 +2693,24 @@ template <ExceptionStyle S> BoxedInt* lenInternal(Box* obj, LenRewriteArgs* rewr ...@@ -2742,12 +2693,24 @@ template <ExceptionStyle S> BoxedInt* lenInternal(Box* obj, LenRewriteArgs* rewr
Box* rtn; Box* rtn;
try { try {
if (rewrite_args) { if (rewrite_args) {
CallRewriteArgs crewrite_args(rewrite_args->rewriter, rewrite_args->obj, rewrite_args->destination); CallattrRewriteArgs crewrite_args(rewrite_args->rewriter, rewrite_args->obj, rewrite_args->destination);
rtn = callattrInternal0<CXX>(obj, len_str, CLASS_ONLY, &crewrite_args, ArgPassSpec(0)); rtn = callattrInternal0<CXX>(obj, len_str, CLASS_ONLY, &crewrite_args, ArgPassSpec(0));
if (!crewrite_args.out_success) if (!crewrite_args.isSuccessful())
rewrite_args = NULL; rewrite_args = NULL;
else if (rtn) else {
rewrite_args->out_rtn = crewrite_args.out_rtn; RewriterVar* rtn;
ReturnConvention return_convention;
std::tie(rtn, return_convention) = crewrite_args.getReturn();
if (return_convention != ReturnConvention::HAS_RETURN
&& return_convention != ReturnConvention::NO_RETURN)
rewrite_args = NULL;
else {
rewrite_args->out_rtn = rtn;
}
if (rewrite_args)
assert((bool)rtn == (return_convention == ReturnConvention::HAS_RETURN));
}
} else { } else {
rtn = callattrInternal0<CXX>(obj, len_str, CLASS_ONLY, NULL, ArgPassSpec(0)); rtn = callattrInternal0<CXX>(obj, len_str, CLASS_ONLY, NULL, ArgPassSpec(0));
} }
...@@ -2851,7 +2814,7 @@ extern "C" i64 unboxedLen(Box* obj) { ...@@ -2851,7 +2814,7 @@ extern "C" i64 unboxedLen(Box* obj) {
// For rewriting purposes, this function assumes that nargs will be constant. // For rewriting purposes, this function assumes that nargs will be constant.
// That's probably fine for some uses (ex binops), but otherwise it should be guarded on beforehand. // That's probably fine for some uses (ex binops), but otherwise it should be guarded on beforehand.
template <ExceptionStyle S> template <ExceptionStyle S>
Box* callattrInternal(Box* obj, BoxedString* attr, LookupScope scope, CallRewriteArgs* rewrite_args, Box* callattrInternal(Box* obj, BoxedString* attr, LookupScope scope, CallattrRewriteArgs* rewrite_args,
ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3, Box** args, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3, Box** args,
const std::vector<BoxedString*>* keyword_names) noexcept(S == CAPI) { const std::vector<BoxedString*>* keyword_names) noexcept(S == CAPI) {
assert(gc::isValidGCObject(attr)); assert(gc::isValidGCObject(attr));
...@@ -2896,19 +2859,29 @@ Box* callattrInternal(Box* obj, BoxedString* attr, LookupScope scope, CallRewrit ...@@ -2896,19 +2859,29 @@ Box* callattrInternal(Box* obj, BoxedString* attr, LookupScope scope, CallRewrit
GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, rewrite_args->obj, Location::any()); GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, rewrite_args->obj, Location::any());
val = getattrInternalEx<S>(obj, attr, &grewrite_args, scope == CLASS_ONLY, true, &bind_obj, &r_bind_obj); val = getattrInternalEx<S>(obj, attr, &grewrite_args, scope == CLASS_ONLY, true, &bind_obj, &r_bind_obj);
// TODO: maybe callattrs should have return conventions as well. // TODO: maybe callattrs should have return conventions as well.
if (!grewrite_args.out_success || grewrite_args.out_return_convention == GetattrRewriteArgs::NOEXC_POSSIBLE) {
if (!grewrite_args.isSuccessful())
rewrite_args = NULL; rewrite_args = NULL;
} else if (val) { else {
assert(grewrite_args.out_return_convention == GetattrRewriteArgs::VALID_RETURN); RewriterVar* rtn;
r_val = grewrite_args.out_rtn; ReturnConvention return_convention;
std::tie(rtn, return_convention) = grewrite_args.getReturn();
if (return_convention != ReturnConvention::HAS_RETURN && return_convention != ReturnConvention::NO_RETURN)
rewrite_args = NULL;
else
r_val = rtn;
if (rewrite_args)
assert((bool)val == (return_convention == ReturnConvention::HAS_RETURN));
} }
} else { } else {
val = getattrInternalEx<S>(obj, attr, NULL, scope == CLASS_ONLY, true, &bind_obj, &r_bind_obj); val = getattrInternalEx<S>(obj, attr, NULL, scope == CLASS_ONLY, true, &bind_obj, &r_bind_obj);
} }
if (val == NULL) { if (val == NULL) {
if (rewrite_args && (S == CXX || !PyErr_Occurred())) if (rewrite_args)
rewrite_args->out_success = true; rewrite_args->setReturn(NULL, ReturnConvention::NO_RETURN);
return val; return val;
} }
...@@ -2968,14 +2941,23 @@ Box* callattrInternal(Box* obj, BoxedString* attr, LookupScope scope, CallRewrit ...@@ -2968,14 +2941,23 @@ Box* callattrInternal(Box* obj, BoxedString* attr, LookupScope scope, CallRewrit
else else
arg_array->setAttr(8, rewrite_args->rewriter->loadConst(0)); arg_array->setAttr(8, rewrite_args->rewriter->loadConst(0));
rewrite_args->out_rtn = rewrite_args->rewriter->call(true, (void*)Helper::call, arg_vec); auto r_rtn = rewrite_args->rewriter->call(true, (void*)Helper::call, arg_vec);
rewrite_args->out_success = true; rewrite_args->setReturn(r_rtn, S == CXX ? ReturnConvention::HAS_RETURN : ReturnConvention::CAPI_RETURN);
void* _args[2] = { args, const_cast<std::vector<BoxedString*>*>(keyword_names) }; void* _args[2] = { args, const_cast<std::vector<BoxedString*>*>(keyword_names) };
return Helper::call(val, argspec, arg1, arg2, arg3, _args); return Helper::call(val, argspec, arg1, arg2, arg3, _args);
} }
return runtimeCallInternal<S>(val, rewrite_args, argspec, arg1, arg2, arg3, args, keyword_names); if (rewrite_args) {
CallRewriteArgs crewrite_args(rewrite_args);
Box* r = runtimeCallInternal<S>(val, &crewrite_args, argspec, arg1, arg2, arg3, args, keyword_names);
if (crewrite_args.out_success)
rewrite_args->setReturn(crewrite_args.out_rtn,
S == CXX ? ReturnConvention::HAS_RETURN : ReturnConvention::CAPI_RETURN);
return r;
} else {
return runtimeCallInternal<S>(val, NULL, argspec, arg1, arg2, arg3, args, keyword_names);
}
} }
template <ExceptionStyle S> template <ExceptionStyle S>
...@@ -3036,7 +3018,7 @@ Box* _callattrEntry(Box* obj, BoxedString* attr, CallattrFlags flags, Box* arg1, ...@@ -3036,7 +3018,7 @@ Box* _callattrEntry(Box* obj, BoxedString* attr, CallattrFlags flags, Box* arg1,
// or this kind of thing is necessary in a lot more places // or this kind of thing is necessary in a lot more places
// rewriter->getArg(3).addGuard(npassed_args); // rewriter->getArg(3).addGuard(npassed_args);
CallRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0), rewriter->getReturnDestination()); CallattrRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0), rewriter->getReturnDestination());
if (npassed_args >= 1) if (npassed_args >= 1)
rewrite_args.arg1 = rewriter->getArg(3); rewrite_args.arg1 = rewriter->getArg(3);
if (npassed_args >= 2) if (npassed_args >= 2)
...@@ -3048,13 +3030,21 @@ Box* _callattrEntry(Box* obj, BoxedString* attr, CallattrFlags flags, Box* arg1, ...@@ -3048,13 +3030,21 @@ Box* _callattrEntry(Box* obj, BoxedString* attr, CallattrFlags flags, Box* arg1,
rtn = callattrInternal<S>(obj, attr, scope, &rewrite_args, argspec, arg1, arg2, arg3, args, keyword_names); rtn = callattrInternal<S>(obj, attr, scope, &rewrite_args, argspec, arg1, arg2, arg3, args, keyword_names);
assert(!(S == CAPI && flags.null_on_nonexistent)); assert(!(S == CAPI && flags.null_on_nonexistent));
if (!rewrite_args.out_success) { if (!rewrite_args.isSuccessful()) {
rewriter.reset(NULL); rewriter.reset(NULL);
} else if (rtn || S == CAPI) { } else {
rewriter->commitReturning(rewrite_args.out_rtn); RewriterVar* rtn;
} else if (flags.null_on_nonexistent) { ReturnConvention return_convention;
assert(!rewrite_args.out_rtn); std::tie(rtn, return_convention) = rewrite_args.getReturn();
rewriter->commitReturning(rewriter->loadConst(0, rewriter->getReturnDestination()));
if (return_convention == ReturnConvention::HAS_RETURN
|| (S == CAPI && return_convention == ReturnConvention::CAPI_RETURN)) {
assert(rtn);
rewriter->commitReturning(rtn);
} else if (return_convention == ReturnConvention::NO_RETURN && flags.null_on_nonexistent) {
assert(!rtn);
rewriter->commitReturning(rewriter->loadConst(0, rewriter->getReturnDestination()));
}
} }
} else { } else {
rtn = callattrInternal<S>(obj, attr, scope, NULL, argspec, arg1, arg2, arg3, args, keyword_names); rtn = callattrInternal<S>(obj, attr, scope, NULL, argspec, arg1, arg2, arg3, args, keyword_names);
...@@ -3081,7 +3071,7 @@ extern "C" Box* callattrCapi(Box* obj, BoxedString* attr, CallattrFlags flags, B ...@@ -3081,7 +3071,7 @@ extern "C" Box* callattrCapi(Box* obj, BoxedString* attr, CallattrFlags flags, B
__builtin_extract_return_addr(__builtin_return_address(0))); __builtin_extract_return_addr(__builtin_return_address(0)));
} }
static inline RewriterVar* getArg(int idx, CallRewriteArgs* rewrite_args) { static inline RewriterVar* getArg(int idx, _CallRewriteArgsBase* rewrite_args) {
if (idx == 0) if (idx == 0)
return rewrite_args->arg1; return rewrite_args->arg1;
if (idx == 1) if (idx == 1)
...@@ -3206,8 +3196,8 @@ static Box* _callFuncHelper(BoxedFunctionBase* func, ArgPassSpec argspec, Box* a ...@@ -3206,8 +3196,8 @@ static Box* _callFuncHelper(BoxedFunctionBase* func, ArgPassSpec argspec, Box* a
typedef std::function<Box*(int, int, RewriterVar*&)> GetDefaultFunc; typedef std::function<Box*(int, int, RewriterVar*&)> GetDefaultFunc;
ArgPassSpec bindObjIntoArgs(Box* bind_obj, RewriterVar* r_bind_obj, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, ArgPassSpec bindObjIntoArgs(Box* bind_obj, RewriterVar* r_bind_obj, _CallRewriteArgsBase* rewrite_args,
Box*& arg1, Box*& arg2, Box*& arg3, Box** args, Box** new_args) { ArgPassSpec argspec, Box*& arg1, Box*& arg2, Box*& arg3, Box** args, Box** new_args) {
int npassed_args = argspec.totalPassed(); int npassed_args = argspec.totalPassed();
assert((new_args != NULL) == (npassed_args >= 3)); assert((new_args != NULL) == (npassed_args >= 3));
...@@ -3235,7 +3225,7 @@ ArgPassSpec bindObjIntoArgs(Box* bind_obj, RewriterVar* r_bind_obj, CallRewriteA ...@@ -3235,7 +3225,7 @@ ArgPassSpec bindObjIntoArgs(Box* bind_obj, RewriterVar* r_bind_obj, CallRewriteA
} }
void rearrangeArguments(ParamReceiveSpec paramspec, const ParamNames* param_names, const char* func_name, void rearrangeArguments(ParamReceiveSpec paramspec, const ParamNames* param_names, const char* func_name,
Box** defaults, CallRewriteArgs* rewrite_args, bool& rewrite_success, ArgPassSpec argspec, Box** defaults, _CallRewriteArgsBase* rewrite_args, bool& rewrite_success, ArgPassSpec argspec,
Box*& oarg1, Box*& oarg2, Box*& oarg3, Box** args, Box** oargs, Box*& oarg1, Box*& oarg2, Box*& oarg3, Box** args, Box** oargs,
const std::vector<BoxedString*>* keyword_names) { const std::vector<BoxedString*>* keyword_names) {
/* /*
...@@ -4017,8 +4007,27 @@ Box* runtimeCallInternal(Box* obj, CallRewriteArgs* rewrite_args, ArgPassSpec ar ...@@ -4017,8 +4007,27 @@ Box* runtimeCallInternal(Box* obj, CallRewriteArgs* rewrite_args, ArgPassSpec ar
} }
if (rewrite_args) { if (rewrite_args) {
rtn = callattrInternal<S>(obj, call_str, CLASS_ONLY, rewrite_args, argspec, arg1, arg2, arg3, args, CallattrRewriteArgs crewrite_args(rewrite_args);
rtn = callattrInternal<S>(obj, call_str, CLASS_ONLY, &crewrite_args, argspec, arg1, arg2, arg3, args,
keyword_names); keyword_names);
if (!crewrite_args.isSuccessful())
rewrite_args = NULL;
else {
RewriterVar* rtn;
ReturnConvention return_convention;
std::tie(rtn, return_convention) = crewrite_args.getReturn();
if (return_convention == ReturnConvention::HAS_RETURN) {
rewrite_args->out_rtn = rtn;
rewrite_args->out_success = true;
} else if (return_convention == ReturnConvention::NO_RETURN) {
// Could handle this, but currently don't, and probably not that important.
rewrite_args = NULL;
} else {
rewrite_args = NULL;
}
}
} else { } else {
rtn = callattrInternal<S>(obj, call_str, CLASS_ONLY, NULL, argspec, arg1, arg2, arg3, args, keyword_names); rtn = callattrInternal<S>(obj, call_str, CLASS_ONLY, NULL, argspec, arg1, arg2, arg3, args, keyword_names);
} }
...@@ -4026,8 +4035,7 @@ Box* runtimeCallInternal(Box* obj, CallRewriteArgs* rewrite_args, ArgPassSpec ar ...@@ -4026,8 +4035,7 @@ Box* runtimeCallInternal(Box* obj, CallRewriteArgs* rewrite_args, ArgPassSpec ar
if (!rtn) { if (!rtn) {
if (S == CAPI) { if (S == CAPI) {
if (!PyErr_Occurred()) { if (!PyErr_Occurred()) {
if (rewrite_args) assert(!rewrite_args); // would need to rewrite this.
rewrite_args->out_success = false;
PyErr_Format(TypeError, "'%s' object is not callable", getTypeName(obj)); PyErr_Format(TypeError, "'%s' object is not callable", getTypeName(obj));
} }
return NULL; return NULL;
...@@ -4240,20 +4248,31 @@ extern "C" Box* binopInternal(Box* lhs, Box* rhs, int op_type, bool inplace, Bin ...@@ -4240,20 +4248,31 @@ extern "C" Box* binopInternal(Box* lhs, Box* rhs, int op_type, bool inplace, Bin
rewrite_args->rhs->addAttrGuard(offsetof(Box, cls), (intptr_t)rhs->cls); rewrite_args->rhs->addAttrGuard(offsetof(Box, cls), (intptr_t)rhs->cls);
} }
struct NotImplementedHelper {
static void call(Box* r, bool was_notimplemented) { assert((r == NotImplemented) == was_notimplemented); }
};
Box* irtn = NULL; Box* irtn = NULL;
if (inplace) { if (inplace) {
BoxedString* iop_name = getInplaceOpName(op_type); BoxedString* iop_name = getInplaceOpName(op_type);
if (rewrite_args) { if (rewrite_args) {
CallRewriteArgs srewrite_args(rewrite_args->rewriter, rewrite_args->lhs, rewrite_args->destination); CallattrRewriteArgs srewrite_args(rewrite_args->rewriter, rewrite_args->lhs, rewrite_args->destination);
srewrite_args.arg1 = rewrite_args->rhs; srewrite_args.arg1 = rewrite_args->rhs;
srewrite_args.args_guarded = true; srewrite_args.args_guarded = true;
irtn = callattrInternal1<CXX>(lhs, iop_name, CLASS_ONLY, &srewrite_args, ArgPassSpec(1), rhs); irtn = callattrInternal1<CXX>(lhs, iop_name, CLASS_ONLY, &srewrite_args, ArgPassSpec(1), rhs);
if (!srewrite_args.out_success) { if (!srewrite_args.isSuccessful()) {
rewrite_args = NULL; rewrite_args = NULL;
} else if (irtn) { } else if (irtn) {
if (irtn != NotImplemented) rewrite_args->out_rtn = srewrite_args.getReturn(ReturnConvention::HAS_RETURN);
rewrite_args->out_rtn = srewrite_args.out_rtn; // If we allowed a rewrite to get here, it means that we assumed that the class will return NotImplemented
// or not based only on the types of the inputs.
#ifndef NDEBUG
rewrite_args->rewriter->call(false, (void*)NotImplementedHelper::call, rewrite_args->out_rtn,
rewrite_args->rewriter->loadConst(irtn == NotImplemented));
#endif
} else {
srewrite_args.assertReturnConvention(ReturnConvention::NO_RETURN);
} }
} else { } else {
irtn = callattrInternal1<CXX>(lhs, iop_name, CLASS_ONLY, NULL, ArgPassSpec(1), rhs); irtn = callattrInternal1<CXX>(lhs, iop_name, CLASS_ONLY, NULL, ArgPassSpec(1), rhs);
...@@ -4262,9 +4281,12 @@ extern "C" Box* binopInternal(Box* lhs, Box* rhs, int op_type, bool inplace, Bin ...@@ -4262,9 +4281,12 @@ extern "C" Box* binopInternal(Box* lhs, Box* rhs, int op_type, bool inplace, Bin
if (irtn) { if (irtn) {
if (irtn != NotImplemented) { if (irtn != NotImplemented) {
if (rewrite_args) { if (rewrite_args) {
assert(rewrite_args->out_rtn);
rewrite_args->out_success = true; rewrite_args->out_success = true;
} }
return irtn; return irtn;
} else {
assert(!rewrite_args);
} }
} }
} }
...@@ -4272,15 +4294,22 @@ extern "C" Box* binopInternal(Box* lhs, Box* rhs, int op_type, bool inplace, Bin ...@@ -4272,15 +4294,22 @@ extern "C" Box* binopInternal(Box* lhs, Box* rhs, int op_type, bool inplace, Bin
BoxedString* op_name = getOpName(op_type); BoxedString* op_name = getOpName(op_type);
Box* lrtn; Box* lrtn;
if (rewrite_args) { if (rewrite_args) {
CallRewriteArgs srewrite_args(rewrite_args->rewriter, rewrite_args->lhs, rewrite_args->destination); CallattrRewriteArgs srewrite_args(rewrite_args->rewriter, rewrite_args->lhs, rewrite_args->destination);
srewrite_args.arg1 = rewrite_args->rhs; srewrite_args.arg1 = rewrite_args->rhs;
lrtn = callattrInternal1<CXX>(lhs, op_name, CLASS_ONLY, &srewrite_args, ArgPassSpec(1), rhs); lrtn = callattrInternal1<CXX>(lhs, op_name, CLASS_ONLY, &srewrite_args, ArgPassSpec(1), rhs);
if (!srewrite_args.out_success) if (!srewrite_args.isSuccessful()) {
rewrite_args = NULL; rewrite_args = NULL;
else if (lrtn) { } else if (lrtn) {
if (lrtn != NotImplemented) rewrite_args->out_rtn = srewrite_args.getReturn(ReturnConvention::HAS_RETURN);
rewrite_args->out_rtn = srewrite_args.out_rtn; // If we allowed a rewrite to get here, it means that we assumed that the class will return NotImplemented
// or not based only on the types of the inputs.
#ifndef NDEBUG
rewrite_args->rewriter->call(false, (void*)NotImplementedHelper::call, rewrite_args->out_rtn,
rewrite_args->rewriter->loadConst(irtn == NotImplemented));
#endif
} else {
srewrite_args.assertReturnConvention(ReturnConvention::NO_RETURN);
} }
} else { } else {
lrtn = callattrInternal1<CXX>(lhs, op_name, CLASS_ONLY, NULL, ArgPassSpec(1), rhs); lrtn = callattrInternal1<CXX>(lhs, op_name, CLASS_ONLY, NULL, ArgPassSpec(1), rhs);
...@@ -4290,6 +4319,7 @@ extern "C" Box* binopInternal(Box* lhs, Box* rhs, int op_type, bool inplace, Bin ...@@ -4290,6 +4319,7 @@ extern "C" Box* binopInternal(Box* lhs, Box* rhs, int op_type, bool inplace, Bin
if (lrtn) { if (lrtn) {
if (lrtn != NotImplemented) { if (lrtn != NotImplemented) {
if (rewrite_args) { if (rewrite_args) {
assert(rewrite_args->out_rtn);
rewrite_args->out_success = true; rewrite_args->out_success = true;
} }
return lrtn; return lrtn;
...@@ -4297,6 +4327,8 @@ extern "C" Box* binopInternal(Box* lhs, Box* rhs, int op_type, bool inplace, Bin ...@@ -4297,6 +4327,8 @@ extern "C" Box* binopInternal(Box* lhs, Box* rhs, int op_type, bool inplace, Bin
} }
// TODO patch these cases // TODO patch these cases
// actually, I think our guarding up to here is correct; the issue is we won't be able to complete
// the rewrite since we have more guards to do, but we already did some mutations.
if (rewrite_args) { if (rewrite_args) {
assert(rewrite_args->out_success == false); assert(rewrite_args->out_success == false);
rewrite_args = NULL; rewrite_args = NULL;
...@@ -4517,14 +4549,25 @@ Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs* rewrit ...@@ -4517,14 +4549,25 @@ Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs* rewrit
Box* contained; Box* contained;
RewriterVar* r_contained = NULL; RewriterVar* r_contained = NULL;
if (rewrite_args) { if (rewrite_args) {
CallRewriteArgs crewrite_args(rewrite_args->rewriter, rewrite_args->rhs, rewrite_args->destination); CallattrRewriteArgs crewrite_args(rewrite_args->rewriter, rewrite_args->rhs, rewrite_args->destination);
crewrite_args.arg1 = rewrite_args->lhs; crewrite_args.arg1 = rewrite_args->lhs;
contained = callattrInternal1<CXX>(rhs, contains_str, CLASS_ONLY, &crewrite_args, ArgPassSpec(1), lhs); contained = callattrInternal1<CXX>(rhs, contains_str, CLASS_ONLY, &crewrite_args, ArgPassSpec(1), lhs);
if (!crewrite_args.out_success) if (!crewrite_args.isSuccessful())
rewrite_args = NULL; rewrite_args = NULL;
else if (contained) else {
r_contained = crewrite_args.out_rtn; RewriterVar* rtn;
ReturnConvention return_convention;
std::tie(rtn, return_convention) = crewrite_args.getReturn();
if (return_convention != ReturnConvention::HAS_RETURN
&& return_convention != ReturnConvention::NO_RETURN)
rewrite_args = NULL;
else
r_contained = rtn;
if (rewrite_args)
assert((bool)contained == (return_convention == ReturnConvention::HAS_RETURN));
}
} else { } else {
contained = callattrInternal1<CXX>(rhs, contains_str, CLASS_ONLY, NULL, ArgPassSpec(1), lhs); contained = callattrInternal1<CXX>(rhs, contains_str, CLASS_ONLY, NULL, ArgPassSpec(1), lhs);
} }
...@@ -4623,14 +4666,24 @@ Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs* rewrit ...@@ -4623,14 +4666,24 @@ Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs* rewrit
Box* lrtn; Box* lrtn;
if (rewrite_args) { if (rewrite_args) {
CallRewriteArgs crewrite_args(rewrite_args->rewriter, rewrite_args->lhs, rewrite_args->destination); CallattrRewriteArgs crewrite_args(rewrite_args->rewriter, rewrite_args->lhs, rewrite_args->destination);
crewrite_args.arg1 = rewrite_args->rhs; crewrite_args.arg1 = rewrite_args->rhs;
lrtn = callattrInternal1<CXX>(lhs, op_name, CLASS_ONLY, &crewrite_args, ArgPassSpec(1), rhs); lrtn = callattrInternal1<CXX>(lhs, op_name, CLASS_ONLY, &crewrite_args, ArgPassSpec(1), rhs);
if (!crewrite_args.out_success) if (!crewrite_args.isSuccessful()) {
rewrite_args = NULL; rewrite_args = NULL;
else if (lrtn) } else {
rewrite_args->out_rtn = crewrite_args.out_rtn; RewriterVar* rtn;
ReturnConvention return_convention;
std::tie(rtn, return_convention) = crewrite_args.getReturn();
if (return_convention != ReturnConvention::HAS_RETURN && return_convention != ReturnConvention::NO_RETURN)
rewrite_args = NULL;
else
rewrite_args->out_rtn = rtn;
if (rewrite_args)
assert((bool)lrtn == (return_convention == ReturnConvention::HAS_RETURN));
}
} else { } else {
lrtn = callattrInternal1<CXX>(lhs, op_name, CLASS_ONLY, NULL, ArgPassSpec(1), rhs); lrtn = callattrInternal1<CXX>(lhs, op_name, CLASS_ONLY, NULL, ArgPassSpec(1), rhs);
} }
...@@ -4757,12 +4810,16 @@ extern "C" Box* unaryop(Box* operand, int op_type) { ...@@ -4757,12 +4810,16 @@ extern "C" Box* unaryop(Box* operand, int op_type) {
Box* rtn = NULL; Box* rtn = NULL;
if (rewriter.get()) { if (rewriter.get()) {
CallRewriteArgs srewrite_args(rewriter.get(), rewriter->getArg(0), rewriter->getReturnDestination()); CallattrRewriteArgs srewrite_args(rewriter.get(), rewriter->getArg(0), rewriter->getReturnDestination());
rtn = callattrInternal0<CXX>(operand, op_name, CLASS_ONLY, &srewrite_args, ArgPassSpec(0)); rtn = callattrInternal0<CXX>(operand, op_name, CLASS_ONLY, &srewrite_args, ArgPassSpec(0));
if (srewrite_args.out_success && rtn)
rewriter->commitReturning(srewrite_args.out_rtn); if (srewrite_args.isSuccessful()) {
else RewriterVar* rtn;
rewriter.reset(); ReturnConvention return_convention;
std::tie(rtn, return_convention) = srewrite_args.getReturn();
if (return_convention == ReturnConvention::HAS_RETURN)
rewriter->commitReturning(rtn);
}
} else } else
rtn = callattrInternal0<CXX>(operand, op_name, CLASS_ONLY, NULL, ArgPassSpec(0)); rtn = callattrInternal0<CXX>(operand, op_name, CLASS_ONLY, NULL, ArgPassSpec(0));
...@@ -4775,10 +4832,29 @@ extern "C" Box* unaryop(Box* operand, int op_type) { ...@@ -4775,10 +4832,29 @@ extern "C" Box* unaryop(Box* operand, int op_type) {
template <ExceptionStyle S> template <ExceptionStyle S>
static Box* callItemAttr(Box* target, BoxedString* item_str, Box* item, Box* value, static Box* callItemAttr(Box* target, BoxedString* item_str, Box* item, Box* value,
CallRewriteArgs* rewrite_args) noexcept(S == CAPI) { CallRewriteArgs* rewrite_args) noexcept(S == CAPI) {
if (value) {
return callattrInternal2<S>(target, item_str, CLASS_ONLY, rewrite_args, ArgPassSpec(2), item, value); if (rewrite_args) {
CallattrRewriteArgs crewrite_args(rewrite_args);
Box* r;
if (value)
r = callattrInternal2<S>(target, item_str, CLASS_ONLY, &crewrite_args, ArgPassSpec(2), item, value);
else
r = callattrInternal1<S>(target, item_str, CLASS_ONLY, &crewrite_args, ArgPassSpec(1), item);
if (crewrite_args.isSuccessful()) {
rewrite_args->out_success = true;
if (r || PyErr_Occurred())
rewrite_args->out_rtn
= crewrite_args.getReturn(S == CAPI ? ReturnConvention::CAPI_RETURN : ReturnConvention::HAS_RETURN);
else
rewrite_args->out_rtn = crewrite_args.getReturn(ReturnConvention::NO_RETURN);
}
return r;
} else { } else {
return callattrInternal1<S>(target, item_str, CLASS_ONLY, rewrite_args, ArgPassSpec(1), item); if (value)
return callattrInternal2<S>(target, item_str, CLASS_ONLY, NULL, ArgPassSpec(2), item, value);
else
return callattrInternal1<S>(target, item_str, CLASS_ONLY, NULL, ArgPassSpec(1), item);
} }
} }
...@@ -4809,11 +4885,17 @@ static Box* callItemOrSliceAttr(Box* target, BoxedString* item_str, BoxedString* ...@@ -4809,11 +4885,17 @@ static Box* callItemOrSliceAttr(Box* target, BoxedString* item_str, BoxedString*
RewriterVar* target_cls = rewrite_args->obj->getAttr(offsetof(Box, cls)); RewriterVar* target_cls = rewrite_args->obj->getAttr(offsetof(Box, cls));
GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, target_cls, Location::any()); GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, target_cls, Location::any());
slice_attr = typeLookup(target->cls, slice_str, &grewrite_args); slice_attr = typeLookup(target->cls, slice_str, &grewrite_args);
if (!grewrite_args.out_success) { if (!grewrite_args.isSuccessful()) {
rewrite_args = NULL; rewrite_args = NULL;
} else { } else {
assert(grewrite_args.out_return_convention RewriterVar* rtn;
== (slice_attr ? GetattrRewriteArgs::VALID_RETURN : GetattrRewriteArgs::NO_RETURN)); ReturnConvention return_convention;
std::tie(rtn, return_convention) = grewrite_args.getReturn();
if (return_convention != ReturnConvention::HAS_RETURN && return_convention != ReturnConvention::NO_RETURN)
rewrite_args = NULL;
if (rewrite_args)
assert((bool)slice_attr == (return_convention == ReturnConvention::HAS_RETURN));
} }
} else { } else {
slice_attr = typeLookup(target->cls, slice_str, NULL); slice_attr = typeLookup(target->cls, slice_str, NULL);
...@@ -4875,12 +4957,27 @@ static Box* callItemOrSliceAttr(Box* target, BoxedString* item_str, BoxedString* ...@@ -4875,12 +4957,27 @@ static Box* callItemOrSliceAttr(Box* target, BoxedString* item_str, BoxedString*
Box* boxedStart = boxInt(start); Box* boxedStart = boxInt(start);
Box* boxedStop = boxInt(stop); Box* boxedStop = boxInt(stop);
if (value) { if (rewrite_args) {
return callattrInternal3<S>(target, slice_str, CLASS_ONLY, rewrite_args, ArgPassSpec(3), boxedStart, CallattrRewriteArgs crewrite_args(rewrite_args);
boxedStop, value); Box* r;
if (value)
r = callattrInternal3<S>(target, slice_str, CLASS_ONLY, &crewrite_args, ArgPassSpec(3), boxedStart,
boxedStop, value);
else
r = callattrInternal2<S>(target, slice_str, CLASS_ONLY, &crewrite_args, ArgPassSpec(2), boxedStart,
boxedStop);
if (crewrite_args.isSuccessful()) {
rewrite_args->out_success = true;
rewrite_args->out_rtn = crewrite_args.getReturn(ReturnConvention::HAS_RETURN);
}
return r;
} else { } else {
return callattrInternal2<S>(target, slice_str, CLASS_ONLY, rewrite_args, ArgPassSpec(2), boxedStart, if (value)
boxedStop); return callattrInternal3<S>(target, slice_str, CLASS_ONLY, NULL, ArgPassSpec(3), boxedStart, boxedStop,
value);
else
return callattrInternal2<S>(target, slice_str, CLASS_ONLY, NULL, ArgPassSpec(2), boxedStart, boxedStop);
} }
} }
} }
...@@ -5287,22 +5384,18 @@ extern "C" Box* createBoxedIterWrapperIfNeeded(Box* o) { ...@@ -5287,22 +5384,18 @@ extern "C" Box* createBoxedIterWrapperIfNeeded(Box* o) {
RewriterVar* r_cls = r_o->getAttr(offsetof(Box, cls)); RewriterVar* r_cls = r_o->getAttr(offsetof(Box, cls));
GetattrRewriteArgs rewrite_args(rewriter.get(), r_cls, rewriter->getReturnDestination()); GetattrRewriteArgs rewrite_args(rewriter.get(), r_cls, rewriter->getReturnDestination());
Box* r = typeLookup(o->cls, hasnext_str, &rewrite_args); Box* r = typeLookup(o->cls, hasnext_str, &rewrite_args);
if (!rewrite_args.out_success) { if (!rewrite_args.isSuccessful()) {
rewriter.reset(NULL); rewriter.reset(NULL);
} else if (r) { } else if (r) {
assert(rewrite_args.out_return_convention == GetattrRewriteArgs::VALID_RETURN); RewriterVar* rtn = rewrite_args.getReturn(ReturnConvention::HAS_RETURN);
rewrite_args.out_rtn->addGuard((uint64_t)r); rtn->addGuard((uint64_t)r);
if (rewrite_args.out_success) { rewriter->commitReturning(r_o);
rewriter->commitReturning(r_o); return o;
return o; } else /* if (!r) */ {
} rewrite_args.assertReturnConvention(ReturnConvention::NO_RETURN);
} else if (!r) {
assert(rewrite_args.out_return_convention == GetattrRewriteArgs::NO_RETURN);
RewriterVar* var = rewriter.get()->call(true, (void*)createBoxedIterWrapper, rewriter->getArg(0)); RewriterVar* var = rewriter.get()->call(true, (void*)createBoxedIterWrapper, rewriter->getArg(0));
if (rewrite_args.out_success) { rewriter->commitReturning(var);
rewriter->commitReturning(var); return createBoxedIterWrapper(o);
return createBoxedIterWrapper(o);
}
} }
} }
...@@ -5797,18 +5890,15 @@ extern "C" Box* getGlobal(Box* globals, BoxedString* name) { ...@@ -5797,18 +5890,15 @@ extern "C" Box* getGlobal(Box* globals, BoxedString* name) {
GetattrRewriteArgs rewrite_args(rewriter.get(), r_mod, rewriter->getReturnDestination()); GetattrRewriteArgs rewrite_args(rewriter.get(), r_mod, rewriter->getReturnDestination());
r = m->getattr(name, &rewrite_args); r = m->getattr(name, &rewrite_args);
if (!rewrite_args.out_success) { if (!rewrite_args.isSuccessful()) {
rewriter.reset(NULL); rewriter.reset(NULL);
} else { } else {
if (r) rewrite_args.assertReturnConvention(r ? ReturnConvention::HAS_RETURN : ReturnConvention::NO_RETURN);
assert(rewrite_args.out_return_convention == GetattrRewriteArgs::VALID_RETURN);
else
assert(rewrite_args.out_return_convention == GetattrRewriteArgs::NO_RETURN);
} }
if (r) { if (r) {
if (rewriter.get()) { if (rewriter.get())
rewriter->commitReturning(rewrite_args.out_rtn); rewriter->commitReturning(rewrite_args.getReturn(ReturnConvention::HAS_RETURN));
}
return r; return r;
} }
} else { } else {
...@@ -5841,14 +5931,14 @@ extern "C" Box* getGlobal(Box* globals, BoxedString* name) { ...@@ -5841,14 +5931,14 @@ extern "C" Box* getGlobal(Box* globals, BoxedString* name) {
rewrite_args.obj_shape_guarded = true; // always builtin module rewrite_args.obj_shape_guarded = true; // always builtin module
rtn = builtins_module->getattr(name, &rewrite_args); rtn = builtins_module->getattr(name, &rewrite_args);
if (!rtn || !rewrite_args.out_success) { if (!rewrite_args.isSuccessful())
rewriter.reset(NULL); rewriter.reset(NULL);
else if (rtn) {
auto r_rtn = rewrite_args.getReturn(ReturnConvention::HAS_RETURN);
rewriter->commitReturning(r_rtn);
} else { } else {
assert(rewrite_args.out_return_convention == GetattrRewriteArgs::VALID_RETURN); rewrite_args.getReturn(); // just to make the asserts happy
} rewriter.reset(NULL);
if (rewriter.get()) {
rewriter->commitReturning(rewrite_args.out_rtn);
} }
} else { } else {
rtn = builtins_module->getattr(name, NULL); rtn = builtins_module->getattr(name, NULL);
......
...@@ -141,8 +141,9 @@ enum LookupScope { ...@@ -141,8 +141,9 @@ enum LookupScope {
INST_ONLY = 2, INST_ONLY = 2,
CLASS_OR_INST = 3, CLASS_OR_INST = 3,
}; };
struct CallattrRewriteArgs;
template <ExceptionStyle S> template <ExceptionStyle S>
Box* callattrInternal(Box* obj, BoxedString* attr, LookupScope, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Box* callattrInternal(Box* obj, BoxedString* attr, LookupScope, CallattrRewriteArgs* rewrite_args, ArgPassSpec argspec,
Box* arg1, Box* arg2, Box* arg3, Box** args, Box* arg1, Box* arg2, Box* arg3, Box** args,
const std::vector<BoxedString*>* keyword_names) noexcept(S == CAPI); const std::vector<BoxedString*>* keyword_names) noexcept(S == CAPI);
extern "C" void delattr_internal(Box* obj, BoxedString* attr, bool allow_custom, DelattrRewriteArgs* rewrite_args); extern "C" void delattr_internal(Box* obj, BoxedString* attr, bool allow_custom, DelattrRewriteArgs* rewrite_args);
......
...@@ -19,48 +19,140 @@ ...@@ -19,48 +19,140 @@
namespace pyston { namespace pyston {
struct GetattrRewriteArgs { // We have have a couple different conventions for returning values from getattr-like functions.
Rewriter* rewriter; // For normal code we have just two conventions:
RewriterVar* obj; // - the "normal" convention is that signalling the lack of an attribute is handled by throwing
Location destination; // an exception (via either CAPI or C++ means). This is the only convention that CPython has.
// - our fast "no exception" convention which will return NULL and not throw an exception, not
// even a CAPI exception.
//
// Each function has a specific convention (most are "normal" and a couple of the inner-most ones
// are "no-exception"), and the callers and callees can both know+adhere adhere to it.
//
// For the rewriter, there are a couple more cases, and we won't know which one we will have to
// use until we get to that particular rewrite. So the function will use 'out_return_convention' to
// signal some information about the possible values out_rtn might represent. A future C++ exception can
// usually still happen if any of these are signalled.
// - There is always a valid attribute (HAS_RETURN). out_rtn will be set and point to a non-null object.
// - There is never an attribute (NO_RETURN). out_rtn is null.
// - There is a valid capi return (CAPI_RETURN). out_rtn is set, and either points to a valid object,
// or will be a null value and a C exception is set.
// - NOEXC_POSSIBLE. out_rtn is set, and may point to a null value with no exception set.
//
// UNSPECIFIED is used as an invalid-default to make sure that we don't implicitly assume one
// of the cases when the callee didn't explicitly signal one.
//
enum class ReturnConvention {
UNSPECIFIED,
HAS_RETURN,
NO_RETURN,
CAPI_RETURN,
NOEXC_POSSIBLE,
};
class _ReturnConventionBase {
private:
bool out_success; bool out_success;
RewriterVar* out_rtn; RewriterVar* out_rtn;
ReturnConvention out_return_convention;
bool return_convention_checked;
public:
_ReturnConventionBase()
: out_success(false),
out_rtn(NULL),
out_return_convention(ReturnConvention::UNSPECIFIED),
return_convention_checked(false) {}
#ifndef NDEBUG
~_ReturnConventionBase() {
if (out_success && !std::uncaught_exception())
assert(return_convention_checked && "Didn't check the return convention of this rewrite...");
}
#endif
void setReturn(RewriterVar* out_rtn, ReturnConvention out_return_convention) {
assert(!out_success);
assert(out_return_convention != ReturnConvention::UNSPECIFIED);
assert((out_rtn == NULL) == (out_return_convention == ReturnConvention::NO_RETURN));
assert(out_return_convention != ReturnConvention::UNSPECIFIED);
assert(!return_convention_checked);
this->out_success = true;
this->out_rtn = out_rtn;
this->out_return_convention = out_return_convention;
// I'm mixed on how useful this is; I like the extra checking, but changing the generated
// assembly is risky:
#ifndef NDEBUG
struct Checker {
static void call(Box* b, ReturnConvention r) {
if (r == ReturnConvention::HAS_RETURN) {
assert(b);
assert(!PyErr_Occurred());
} else if (r == ReturnConvention::CAPI_RETURN) {
assert((bool)b ^ (bool)PyErr_Occurred());
} else {
assert(r == ReturnConvention::NOEXC_POSSIBLE);
}
}
};
if (out_rtn) {
auto rewriter = out_rtn->getRewriter();
rewriter->call(false, (void*)Checker::call, out_rtn, rewriter->loadConst((int)out_return_convention));
}
#endif
}
// For convenience for use as rewrite_args->setReturn(other_rewrite_args->getReturn())
void setReturn(std::pair<RewriterVar*, ReturnConvention> p) { setReturn(p.first, p.second); }
void clearReturn() {
assert(out_success);
assert(return_convention_checked && "Didn't check the return convention of this rewrite...");
out_success = false;
out_rtn = NULL;
out_return_convention = ReturnConvention::UNSPECIFIED;
return_convention_checked = false;
}
RewriterVar* getReturn(ReturnConvention required_convention) {
assert(isSuccessful());
assert(this->out_return_convention == required_convention);
return_convention_checked = true;
return this->out_rtn;
}
void assertReturnConvention(ReturnConvention required_convention) {
assert(isSuccessful());
ASSERT(this->out_return_convention == required_convention, "user asked for convention %d but got %d",
required_convention, this->out_return_convention);
return_convention_checked = true;
}
std::pair<RewriterVar*, ReturnConvention> getReturn() {
assert(isSuccessful());
return_convention_checked = true;
return std::make_pair(this->out_rtn, this->out_return_convention);
}
bool isSuccessful() {
assert(out_success == (out_return_convention != ReturnConvention::UNSPECIFIED));
return out_success;
}
};
class GetattrRewriteArgs : public _ReturnConventionBase {
public:
Rewriter* rewriter;
RewriterVar* obj;
Location destination;
public:
bool obj_hcls_guarded; bool obj_hcls_guarded;
bool obj_shape_guarded; // "shape" as in whether there are hcls attrs and where they live bool obj_shape_guarded; // "shape" as in whether there are hcls attrs and where they live
// We have have a couple different conventions for returning values from getattr-like functions.
// For normal code we have just two conventions:
// - the "normal" convention is that signalling the lack of an attribute is handled by throwing
// an exception (via either CAPI or C++ means). This is the only convention that CPython has.
// - our fast "no exception" convention which will return NULL and not throw an exception, not
// even a CAPI exception.
//
// For the rewriter, there are three cases:
// - we will obey the "normal" convention (VALID_RETURN)
// - we will never have anything to return and there will be no exception (NO_RETURN)
// - we don't know which of the above two will happen (NOEXC_POSSIBLE)
//
// UNSPECIFIED is used as an invalid-default to make sure that we don't implicitly assume one
// of the cases when the callee didn't explicitly signal one.
//
enum ReturnConvention {
UNSPECIFIED,
NO_RETURN,
NOEXC_POSSIBLE,
VALID_RETURN,
} out_return_convention;
GetattrRewriteArgs(Rewriter* rewriter, RewriterVar* obj, Location destination) GetattrRewriteArgs(Rewriter* rewriter, RewriterVar* obj, Location destination)
: rewriter(rewriter), : rewriter(rewriter), obj(obj), destination(destination), obj_hcls_guarded(false), obj_shape_guarded(false) {}
obj(obj),
destination(destination),
out_success(false),
out_rtn(NULL),
obj_hcls_guarded(false),
obj_shape_guarded(false),
out_return_convention(UNSPECIFIED) {}
}; };
struct SetattrRewriteArgs { struct SetattrRewriteArgs {
...@@ -95,7 +187,8 @@ struct LenRewriteArgs { ...@@ -95,7 +187,8 @@ struct LenRewriteArgs {
: rewriter(rewriter), obj(obj), destination(destination), out_success(false), out_rtn(NULL) {} : rewriter(rewriter), obj(obj), destination(destination), out_success(false), out_rtn(NULL) {}
}; };
struct CallRewriteArgs { struct _CallRewriteArgsBase {
public:
Rewriter* rewriter; Rewriter* rewriter;
RewriterVar* obj; RewriterVar* obj;
RewriterVar* arg1, *arg2, *arg3, *args; RewriterVar* arg1, *arg2, *arg3, *args;
...@@ -103,10 +196,8 @@ struct CallRewriteArgs { ...@@ -103,10 +196,8 @@ struct CallRewriteArgs {
bool args_guarded; bool args_guarded;
Location destination; Location destination;
bool out_success; _CallRewriteArgsBase(const _CallRewriteArgsBase& copy_from) = default;
RewriterVar* out_rtn; _CallRewriteArgsBase(Rewriter* rewriter, RewriterVar* obj, Location destination)
CallRewriteArgs(Rewriter* rewriter, RewriterVar* obj, Location destination)
: rewriter(rewriter), : rewriter(rewriter),
obj(obj), obj(obj),
arg1(NULL), arg1(NULL),
...@@ -115,9 +206,27 @@ struct CallRewriteArgs { ...@@ -115,9 +206,27 @@ struct CallRewriteArgs {
args(NULL), args(NULL),
func_guarded(false), func_guarded(false),
args_guarded(false), args_guarded(false),
destination(destination), destination(destination) {}
out_success(false), };
out_rtn(NULL) {}
struct CallRewriteArgs : public _CallRewriteArgsBase {
public:
bool out_success;
RewriterVar* out_rtn;
CallRewriteArgs(Rewriter* rewriter, RewriterVar* obj, Location destination)
: _CallRewriteArgsBase(rewriter, obj, destination), out_success(false), out_rtn(NULL) {}
CallRewriteArgs(_CallRewriteArgsBase* copy_from)
: _CallRewriteArgsBase(*copy_from), out_success(false), out_rtn(NULL) {}
};
class CallattrRewriteArgs : public _CallRewriteArgsBase, public _ReturnConventionBase {
public:
CallattrRewriteArgs(Rewriter* rewriter, RewriterVar* obj, Location destination)
: _CallRewriteArgsBase(rewriter, obj, destination) {}
CallattrRewriteArgs(_CallRewriteArgsBase* copy_from) : _CallRewriteArgsBase(*copy_from) {}
}; };
struct GetitemRewriteArgs { struct GetitemRewriteArgs {
...@@ -171,14 +280,14 @@ struct CompareRewriteArgs { ...@@ -171,14 +280,14 @@ struct CompareRewriteArgs {
// TODO Fix this function's signature. should we pass back out through args? the common case is that they // TODO Fix this function's signature. should we pass back out through args? the common case is that they
// match anyway. Or maybe it should call a callback function, which could save on the common case. // match anyway. Or maybe it should call a callback function, which could save on the common case.
void rearrangeArguments(ParamReceiveSpec paramspec, const ParamNames* param_names, const char* func_name, void rearrangeArguments(ParamReceiveSpec paramspec, const ParamNames* param_names, const char* func_name,
Box** defaults, CallRewriteArgs* rewrite_args, bool& rewrite_success, ArgPassSpec argspec, Box** defaults, _CallRewriteArgsBase* rewrite_args, bool& rewrite_success, ArgPassSpec argspec,
Box*& arg1, Box*& arg2, Box*& arg3, Box** args, Box** oargs, Box*& arg1, Box*& arg2, Box*& arg3, Box** args, Box** oargs,
const std::vector<BoxedString*>* keyword_names); const std::vector<BoxedString*>* keyword_names);
// new_args should be allocated by the caller if at least three args get passed in. // new_args should be allocated by the caller if at least three args get passed in.
// rewrite_args will get modified in place. // rewrite_args will get modified in place.
ArgPassSpec bindObjIntoArgs(Box* bind_obj, RewriterVar* r_bind_obj, CallRewriteArgs* rewrite_args, ArgPassSpec argspec, ArgPassSpec bindObjIntoArgs(Box* bind_obj, RewriterVar* r_bind_obj, _CallRewriteArgsBase* rewrite_args,
Box*& arg1, Box*& arg2, Box*& arg3, Box** args, Box** new_args); ArgPassSpec argspec, Box*& arg1, Box*& arg2, Box*& arg3, Box** args, Box** new_args);
} // namespace pyston } // namespace pyston
#endif #endif
...@@ -908,13 +908,12 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo ...@@ -908,13 +908,12 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, r_ccls, rewrite_args->destination); GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, r_ccls, rewrite_args->destination);
// TODO: if tp_new != Py_CallPythonNew, call that instead? // TODO: if tp_new != Py_CallPythonNew, call that instead?
new_attr = typeLookup(cls, new_str, &grewrite_args); new_attr = typeLookup(cls, new_str, &grewrite_args);
assert(new_attr);
if (!grewrite_args.out_success) if (!grewrite_args.isSuccessful())
rewrite_args = NULL; rewrite_args = NULL;
else { else {
assert(new_attr); r_new = grewrite_args.getReturn(ReturnConvention::HAS_RETURN);
assert(grewrite_args.out_return_convention = GetattrRewriteArgs::VALID_RETURN);
r_new = grewrite_args.out_rtn;
r_new->addGuard((intptr_t)new_attr); r_new->addGuard((intptr_t)new_attr);
} }
...@@ -1052,15 +1051,14 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo ...@@ -1052,15 +1051,14 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo
GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, r_ccls, rewrite_args->destination); GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, r_ccls, rewrite_args->destination);
init_attr = typeLookup(cls, init_str, &grewrite_args); init_attr = typeLookup(cls, init_str, &grewrite_args);
if (!grewrite_args.out_success) if (!grewrite_args.isSuccessful())
rewrite_args = NULL; rewrite_args = NULL;
else { else {
if (init_attr) { if (init_attr) {
assert(grewrite_args.out_return_convention = GetattrRewriteArgs::VALID_RETURN); r_init = grewrite_args.getReturn(ReturnConvention::HAS_RETURN);
r_init = grewrite_args.out_rtn;
r_init->addGuard((intptr_t)init_attr); r_init->addGuard((intptr_t)init_attr);
} else { } else {
assert(grewrite_args.out_return_convention = GetattrRewriteArgs::NO_RETURN); grewrite_args.assertReturnConvention(ReturnConvention::NO_RETURN);
} }
} }
} else { } else {
......
class C(object):
def __add__(self, rhs):
if rhs == 50:
return NotImplemented
return 0
__eq__ = __add__
def f():
c = C()
for i in xrange(100):
try:
print i, c + i
except TypeError as e:
print e
f()
def f2():
c = C()
for i in xrange(100):
try:
print i, c == i
except TypeError as e:
print e
f2()
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