Commit 7d839c02 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Add more asserts to aggressively enforce return conventions

You can't get the return value from a RewriteArgs without
looking at the return convention.  Debug mode will check the
return convention during the execution of rewrites.

Split "VALID_RETURN" into "HAS_RETURN" and "CAPI_RETURN" since some
places used it to mean either.

Hopefully this helps keep things clean.  There are a lot of places that
were implictly assuming a certain return convention, but now that they
have to explicitly assume it, the issues are more obvious.  Plus
they will get checked in the debug builds.

Also tried to fix things up while going through and doing this refactoring;
I think I found a number of issues.
parent 8c8e595a
...@@ -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;
} }
...@@ -328,62 +333,71 @@ Box* classobjRepr(Box* _obj) { ...@@ -328,62 +333,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__");
...@@ -398,7 +412,7 @@ static Box* instanceGetattributeWithFallback(BoxedInstance* inst, BoxedString* a ...@@ -398,7 +412,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);
...@@ -411,7 +425,7 @@ static Box* _instanceGetattribute(Box* _inst, BoxedString* attr_str, bool raise_ ...@@ -411,7 +425,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
...@@ -905,13 +905,12 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo ...@@ -905,13 +905,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);
} }
...@@ -1049,15 +1048,14 @@ static Box* typeCallInner(CallRewriteArgs* rewrite_args, ArgPassSpec argspec, Bo ...@@ -1049,15 +1048,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