Commit 6160ed80 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Add a getattr rewrite "return convention"

Previously, we would inspect the combination of (return_value, exception_state)
to try to determine what the behavior of future rewrites will be.  For example,
if no attribute was returned and no exception was thrown, then we would assume
that all future times through the rewrite the behavior would be the same.  This
has caused a few bugs, and I'm about to add other cases where it won't be possible
to examine the current function's return value to determine what the future
rewrites will do.

So instead, have getattr-like functions return a "rewriter return convention" flag
that says how future rewrites will behave.
parent d9084137
...@@ -1044,8 +1044,10 @@ Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs* ...@@ -1044,8 +1044,10 @@ Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs*
if (!grewrite_args.out_success) if (!grewrite_args.out_success)
rewrite_args = NULL; rewrite_args = NULL;
else if (res) else if (res) {
rewrite_args->out_rtn = grewrite_args.out_rtn; rewrite_args->out_rtn = grewrite_args.out_rtn;
rewrite_args->out_return_convention = grewrite_args.out_return_convention;
}
} else { } else {
try { try {
res = getattrInternalGeneric(self, name, NULL, false, false, NULL, NULL); res = getattrInternalGeneric(self, name, NULL, false, false, NULL, NULL);
...@@ -1110,8 +1112,10 @@ Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs* ...@@ -1110,8 +1112,10 @@ Box* slotTpGetattrHookInternal(Box* self, BoxedString* name, GetattrRewriteArgs*
if (!crewrite_args.out_success) if (!crewrite_args.out_success)
rewrite_args = NULL; rewrite_args = NULL;
else else {
rewrite_args->out_rtn = crewrite_args.out_rtn; rewrite_args->out_rtn = crewrite_args.out_rtn;
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
// a second callattr. My guess though is that the gains would be small, so I would prefer to keep // a second callattr. My guess though is that the gains would be small, so I would prefer to keep
......
...@@ -33,6 +33,11 @@ Box* recordType(TypeRecorder* self, Box* obj) { ...@@ -33,6 +33,11 @@ Box* recordType(TypeRecorder* self, Box* obj) {
// The baseline JIT directly generates machine code for this function inside JitFragmentWriter::_emitRecordType. // The baseline JIT directly generates machine code for this function inside JitFragmentWriter::_emitRecordType.
// When changing this function one has to also change the bjit code. // When changing this function one has to also change the bjit code.
if (!obj) {
assert(PyErr_Occurred());
return obj;
}
BoxedClass* cls = obj->cls; BoxedClass* cls = obj->cls;
if (cls != self->last_seen) { if (cls != self->last_seen) {
self->last_seen = cls; self->last_seen = cls;
......
...@@ -735,6 +735,7 @@ Box* Box::getattr(BoxedString* attr, GetattrRewriteArgs* rewrite_args) { ...@@ -735,6 +735,7 @@ Box* Box::getattr(BoxedString* attr, GetattrRewriteArgs* rewrite_args) {
if (offset == -1) { if (offset == -1) {
if (rewrite_args) { if (rewrite_args) {
rewrite_args->out_success = true; rewrite_args->out_success = true;
rewrite_args->out_return_convention = GetattrRewriteArgs::NO_RETURN;
} }
return NULL; return NULL;
} }
...@@ -753,6 +754,8 @@ Box* Box::getattr(BoxedString* attr, GetattrRewriteArgs* rewrite_args) { ...@@ -753,6 +754,8 @@ Box* Box::getattr(BoxedString* attr, GetattrRewriteArgs* rewrite_args) {
if (rewrite_args) { if (rewrite_args) {
rewrite_args->out_success = true; 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];
...@@ -774,6 +777,8 @@ Box* Box::getattr(BoxedString* attr, GetattrRewriteArgs* rewrite_args) { ...@@ -774,6 +777,8 @@ Box* Box::getattr(BoxedString* attr, GetattrRewriteArgs* rewrite_args) {
if (rewrite_args) { if (rewrite_args) {
rewrite_args->out_success = true; rewrite_args->out_success = true;
assert(rewrite_args->out_rtn == NULL);
rewrite_args->out_return_convention = GetattrRewriteArgs::NO_RETURN;
} }
return NULL; return NULL;
...@@ -986,6 +991,9 @@ Box* typeLookup(BoxedClass* cls, BoxedString* attr, GetattrRewriteArgs* rewrite_ ...@@ -986,6 +991,9 @@ Box* typeLookup(BoxedClass* cls, BoxedString* attr, GetattrRewriteArgs* rewrite_
return val; return val;
} }
assert(rewrite_args->out_success);
assert(!rewrite_args->out_rtn);
rewrite_args->out_return_convention = GetattrRewriteArgs::NO_RETURN;
return NULL; return NULL;
} else { } else {
assert(attr->interned_state != SSTATE_NOT_INTERNED); assert(attr->interned_state != SSTATE_NOT_INTERNED);
...@@ -1088,6 +1096,7 @@ Box* nondataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, Box ...@@ -1088,6 +1096,7 @@ Box* nondataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, Box
rewrite_args->out_rtn rewrite_args->out_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->out_success = true;
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 {
...@@ -1095,6 +1104,7 @@ Box* nondataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, Box ...@@ -1095,6 +1104,7 @@ Box* nondataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, Box
if (rewrite_args) { if (rewrite_args) {
rewrite_args->out_rtn = r_im_func; rewrite_args->out_rtn = r_im_func;
rewrite_args->out_success = true; 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;
...@@ -1110,6 +1120,7 @@ Box* nondataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, Box ...@@ -1110,6 +1120,7 @@ Box* nondataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, Box
r_sm_callable->addGuardNotEq(0); r_sm_callable->addGuardNotEq(0);
rewrite_args->out_success = true; rewrite_args->out_success = true;
rewrite_args->out_rtn = r_sm_callable; rewrite_args->out_rtn = r_sm_callable;
rewrite_args->out_return_convention = GetattrRewriteArgs::VALID_RETURN;
} }
return sm->sm_callable; return sm->sm_callable;
...@@ -1128,6 +1139,7 @@ Box* nondataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, Box ...@@ -1128,6 +1139,7 @@ Box* nondataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, Box
rewrite_args->out_success = true; rewrite_args->out_success = true;
rewrite_args->out_rtn = r_rtn; rewrite_args->out_rtn = r_rtn;
rewrite_args->out_return_convention = GetattrRewriteArgs::VALID_RETURN;
} }
return r; return r;
} }
...@@ -1149,6 +1161,7 @@ Box* descriptorClsSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedClass* cls ...@@ -1149,6 +1161,7 @@ Box* descriptorClsSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedClass* cls
rewrite_args->out_rtn rewrite_args->out_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->out_success = true;
rewrite_args->out_return_convention = GetattrRewriteArgs::VALID_RETURN;
} }
return boxUnboundInstanceMethod(descr, cls); return boxUnboundInstanceMethod(descr, cls);
} }
...@@ -1156,6 +1169,7 @@ Box* descriptorClsSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedClass* cls ...@@ -1156,6 +1169,7 @@ Box* descriptorClsSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedClass* cls
if (rewrite_args) { if (rewrite_args) {
rewrite_args->out_success = true; rewrite_args->out_success = true;
rewrite_args->out_rtn = r_descr; rewrite_args->out_rtn = r_descr;
rewrite_args->out_return_convention = GetattrRewriteArgs::VALID_RETURN;
} }
return descr; return descr;
} }
...@@ -1169,6 +1183,7 @@ Box* descriptorClsSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedClass* cls ...@@ -1169,6 +1183,7 @@ Box* descriptorClsSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedClass* cls
if (rewrite_args) { if (rewrite_args) {
rewrite_args->out_rtn = r_descr; rewrite_args->out_rtn = r_descr;
rewrite_args->out_success = true; rewrite_args->out_success = true;
rewrite_args->out_return_convention = GetattrRewriteArgs::VALID_RETURN;
} }
return descr; return descr;
} }
...@@ -1213,6 +1228,7 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS ...@@ -1213,6 +1228,7 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS
rewrite_args->out_rtn = rewrite_args->obj->getAttr(member_desc->offset, rewrite_args->destination); rewrite_args->out_rtn = rewrite_args->obj->getAttr(member_desc->offset, rewrite_args->destination);
rewrite_args->out_rtn->addGuardNotEq(0); rewrite_args->out_rtn->addGuardNotEq(0);
rewrite_args->out_success = true; rewrite_args->out_success = true;
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);
...@@ -1228,6 +1244,7 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS ...@@ -1228,6 +1244,7 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS
// 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); rewrite_args->out_rtn = rewrite_args->rewriter->call(false, (void*)noneIfNull, r_interm);
rewrite_args->out_success = true; rewrite_args->out_success = true;
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);
...@@ -1241,8 +1258,9 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS ...@@ -1241,8 +1258,9 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS
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 rewrite_args->out_rtn
= rewrite_args->rewriter->call(true, (void*)boxFloat, normal_args, float_args); = rewrite_args->rewriter->call(false, (void*)boxFloat, normal_args, float_args);
rewrite_args->out_success = true; 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);
...@@ -1257,6 +1275,7 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS ...@@ -1257,6 +1275,7 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS
rewrite_args->out_rtn rewrite_args->out_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->out_success = true; 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);
...@@ -1269,6 +1288,7 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS ...@@ -1269,6 +1288,7 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS
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); \ rewrite_args->out_rtn = rewrite_args->rewriter->call(true, (void*)boxFn, r_unboxed_val); \
rewrite_args->out_success = true; \ rewrite_args->out_success = true; \
rewrite_args->out_return_convention = GetattrRewriteArgs::VALID_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); \
...@@ -1292,6 +1312,7 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS ...@@ -1292,6 +1312,7 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS
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); rewrite_args->out_rtn = rewrite_args->rewriter->call(true, (void*)boxStringOrNone, r_interm);
rewrite_args->out_success = true; rewrite_args->out_success = true;
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);
...@@ -1303,6 +1324,7 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS ...@@ -1303,6 +1324,7 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS
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->out_success = true;
rewrite_args->out_return_convention = GetattrRewriteArgs::VALID_RETURN;
} }
rewrite_args = NULL; rewrite_args = NULL;
...@@ -1335,6 +1357,7 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS ...@@ -1335,6 +1357,7 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS
} else { } else {
rewrite_args->out_success = true; rewrite_args->out_success = true;
rewrite_args->out_rtn = crewrite_args.out_rtn; rewrite_args->out_rtn = crewrite_args.out_rtn;
rewrite_args->out_return_convention = GetattrRewriteArgs::VALID_RETURN;
} }
return rtn; return rtn;
} }
...@@ -1374,6 +1397,7 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS ...@@ -1374,6 +1397,7 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, BoxedS
rewrite_args->rewriter->checkAndThrowCAPIException(rewrite_args->out_rtn); rewrite_args->rewriter->checkAndThrowCAPIException(rewrite_args->out_rtn);
rewrite_args->out_success = true; 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);
...@@ -1427,6 +1451,7 @@ Box* getattrInternalEx(Box* obj, BoxedString* attr, GetattrRewriteArgs* rewrite_ ...@@ -1427,6 +1451,7 @@ Box* getattrInternalEx(Box* obj, BoxedString* attr, GetattrRewriteArgs* rewrite_
rewrite_args->out_rtn = r_rtn; rewrite_args->out_rtn = r_rtn;
rewrite_args->out_success = true; rewrite_args->out_success = true;
rewrite_args->out_return_convention = GetattrRewriteArgs::VALID_RETURN;
} }
if (!r) { if (!r) {
...@@ -1596,7 +1621,10 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew ...@@ -1596,7 +1621,10 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew
if (!grewrite_args.out_success) { if (!grewrite_args.out_success) {
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.out_rtn; r_descr = grewrite_args.out_rtn;
} else {
assert(grewrite_args.out_return_convention == GetattrRewriteArgs::NO_RETURN);
} }
} else { } else {
descr = typeLookup(obj->cls, attr, NULL); descr = typeLookup(obj->cls, attr, NULL);
...@@ -1698,6 +1726,7 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew ...@@ -1698,6 +1726,7 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew
} else { } else {
rewrite_args->out_success = true; rewrite_args->out_success = true;
rewrite_args->out_rtn = crewrite_args.out_rtn; 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);
...@@ -1723,7 +1752,10 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew ...@@ -1723,7 +1752,10 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew
if (!hrewrite_args.out_success) { if (!hrewrite_args.out_success) {
rewrite_args = NULL; rewrite_args = NULL;
} else if (val) { } else if (val) {
assert(hrewrite_args.out_return_convention == GetattrRewriteArgs::VALID_RETURN);
r_val = hrewrite_args.out_rtn; r_val = hrewrite_args.out_rtn;
} else {
assert(hrewrite_args.out_return_convention == GetattrRewriteArgs::NO_RETURN);
} }
} else { } else {
val = obj->getattr(attr, NULL); val = obj->getattr(attr, NULL);
...@@ -1733,6 +1765,7 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew ...@@ -1733,6 +1765,7 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew
if (rewrite_args) { if (rewrite_args) {
rewrite_args->out_rtn = r_val; rewrite_args->out_rtn = r_val;
rewrite_args->out_success = true; rewrite_args->out_success = true;
rewrite_args->out_return_convention = GetattrRewriteArgs::VALID_RETURN;
} }
return val; return val;
} }
...@@ -1776,6 +1809,7 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew ...@@ -1776,6 +1809,7 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew
if (rewrite_args) { if (rewrite_args) {
rewrite_args->out_rtn = r_val; rewrite_args->out_rtn = r_val;
rewrite_args->out_success = true; rewrite_args->out_success = true;
rewrite_args->out_return_convention = GetattrRewriteArgs::VALID_RETURN;
} }
return val; return val;
} }
...@@ -1791,6 +1825,7 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew ...@@ -1791,6 +1825,7 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew
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->out_success = true;
rewrite_args->out_return_convention = GetattrRewriteArgs::VALID_RETURN;
} }
return r; return r;
...@@ -1837,6 +1872,7 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew ...@@ -1837,6 +1872,7 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew
} else { } else {
rewrite_args->out_success = true; rewrite_args->out_success = true;
rewrite_args->out_rtn = crewrite_args.out_rtn; 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);
...@@ -1850,6 +1886,7 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew ...@@ -1850,6 +1886,7 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew
if (rewrite_args) { if (rewrite_args) {
rewrite_args->out_rtn = r_descr; rewrite_args->out_rtn = r_descr;
rewrite_args->out_success = true; rewrite_args->out_success = true;
rewrite_args->out_return_convention = GetattrRewriteArgs::VALID_RETURN;
} }
return descr; return descr;
} }
...@@ -1863,6 +1900,7 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew ...@@ -1863,6 +1900,7 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew
if (rewrite_args) { if (rewrite_args) {
rewrite_args->out_success = true; rewrite_args->out_success = true;
rewrite_args->out_return_convention = GetattrRewriteArgs::NO_RETURN;
} }
return NULL; return NULL;
} }
...@@ -1939,6 +1977,22 @@ template <ExceptionStyle S> Box* _getattrEntry(Box* obj, BoxedString* attr, void ...@@ -1939,6 +1977,22 @@ template <ExceptionStyle S> Box* _getattrEntry(Box* obj, BoxedString* attr, void
ScopedStatTimer st(counter, 10); ScopedStatTimer st(counter, 10);
#endif #endif
// getattrInternal (what we call) can return NULL without setting an exception, but this function's
// convention is that an exception will need to be thrown.
// Here's a simple helper to help with that:
class NoexcHelper {
public:
static void call(Box* rtn, Box* obj, BoxedString* attr) {
if (S == CAPI) {
if (!rtn && !PyErr_Occurred())
raiseAttributeErrorCapi(obj, attr->s());
} else {
if (!rtn)
raiseAttributeError(obj, attr->s());
}
}
};
Box* val; Box* val;
if (rewriter.get()) { if (rewriter.get()) {
Location dest; Location dest;
...@@ -1951,45 +2005,37 @@ template <ExceptionStyle S> Box* _getattrEntry(Box* obj, BoxedString* attr, void ...@@ -1951,45 +2005,37 @@ template <ExceptionStyle S> Box* _getattrEntry(Box* obj, BoxedString* attr, void
val = getattrInternal<S>(obj, attr, &rewrite_args); val = getattrInternal<S>(obj, attr, &rewrite_args);
if (rewrite_args.out_success) { if (rewrite_args.out_success) {
if (!val) { assert(rewrite_args.out_return_convention != GetattrRewriteArgs::UNSPECIFIED);
if (rewrite_args.out_return_convention != GetattrRewriteArgs::VALID_RETURN) {
if (attr->interned_state == SSTATE_INTERNED_IMMORTAL) { if (attr->interned_state == SSTATE_INTERNED_IMMORTAL) {
if (S == CXX) { if (rewrite_args.out_return_convention == GetattrRewriteArgs::NO_RETURN) {
rewriter->call(true, (void*)raiseAttributeError, rewriter->getArg(0), assert(!rewrite_args.out_rtn);
rewriter->loadConst((intptr_t)attr->data(), Location::forArg(1)), rewrite_args.out_rtn = rewriter->loadConst(0, Location::forArg(1));
rewriter->loadConst(attr->size(), Location::forArg(2)));
rewriter->commit();
} else if (S == CAPI && !PyErr_Occurred()) {
rewriter->call(true, (void*)raiseAttributeErrorCapi, rewriter->getArg(0),
rewriter->loadConst((intptr_t)attr->data(), Location::forArg(1)),
rewriter->loadConst(attr->size(), Location::forArg(2)));
rewriter->commitReturning(rewriter->loadConst(0, rewriter->getReturnDestination()));
} }
rewriter->call(true, (void*)NoexcHelper::call, rewrite_args.out_rtn, rewriter->getArg(0),
rewriter->loadConst((intptr_t)attr, Location::forArg(2)));
rewrite_args.out_return_convention = GetattrRewriteArgs::VALID_RETURN;
}
}
if (rewrite_args.out_return_convention == GetattrRewriteArgs::VALID_RETURN) {
RewriterVar* r_rtn = rewrite_args.out_rtn;
if (recorder) {
r_rtn = rewriter->call(false, (void*)recordType,
rewriter->loadConst((intptr_t)recorder, Location::forArg(0)), r_rtn);
recordType(recorder, val);
} }
} else if (recorder) {
RewriterVar* record_rtn = rewriter->call(false, (void*)recordType,
rewriter->loadConst((intptr_t)recorder, Location::forArg(0)),
rewrite_args.out_rtn);
rewriter->commitReturning(record_rtn);
recordType(recorder, val); rewriter->commitReturning(r_rtn);
} else {
rewriter->commitReturning(rewrite_args.out_rtn);
} }
} }
} else { } else {
val = getattrInternal<S>(obj, attr, NULL); val = getattrInternal<S>(obj, attr, NULL);
} }
if (val) NoexcHelper::call(val, obj, attr);
return val; return val;
if (S == CAPI) {
if (!PyErr_Occurred())
raiseAttributeErrorCapi(obj, attr->s());
return NULL;
} else {
raiseAttributeError(obj, attr->s());
}
} }
extern "C" Box* getattr_capi(Box* obj, BoxedString* attr) noexcept { extern "C" Box* getattr_capi(Box* obj, BoxedString* attr) noexcept {
......
...@@ -30,6 +30,28 @@ struct GetattrRewriteArgs { ...@@ -30,6 +30,28 @@ struct GetattrRewriteArgs {
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), obj(obj),
...@@ -37,7 +59,8 @@ struct GetattrRewriteArgs { ...@@ -37,7 +59,8 @@ struct GetattrRewriteArgs {
out_success(false), out_success(false),
out_rtn(NULL), out_rtn(NULL),
obj_hcls_guarded(false), obj_hcls_guarded(false),
obj_shape_guarded(false) {} obj_shape_guarded(false),
out_return_convention(UNSPECIFIED) {}
}; };
struct SetattrRewriteArgs { struct SetattrRewriteArgs {
......
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