Commit 34532626 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #872 from kmod/perf2

Rewriter "aggressiveness" and backoff
parents d9084137 c105fc2e
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -30,7 +30,6 @@ namespace pyston { ...@@ -30,7 +30,6 @@ namespace pyston {
using namespace pyston::assembler; using namespace pyston::assembler;
#define MEGAMORPHIC_THRESHOLD 100
#define MAX_RETRY_BACKOFF 1024 #define MAX_RETRY_BACKOFF 1024
// TODO not right place for this... // TODO not right place for this...
...@@ -121,7 +120,7 @@ void ICSlotRewrite::commit(CommitHook* hook) { ...@@ -121,7 +120,7 @@ void ICSlotRewrite::commit(CommitHook* hook) {
ic->times_rewritten++; ic->times_rewritten++;
if (ic->times_rewritten == MEGAMORPHIC_THRESHOLD) { if (ic->times_rewritten == IC_MEGAMORPHIC_THRESHOLD) {
static StatCounter megamorphic_ics("megamorphic_ics"); static StatCounter megamorphic_ics("megamorphic_ics");
megamorphic_ics.log(); megamorphic_ics.log();
} }
...@@ -298,6 +297,6 @@ bool ICInfo::shouldAttempt() { ...@@ -298,6 +297,6 @@ bool ICInfo::shouldAttempt() {
} }
bool ICInfo::isMegamorphic() { bool ICInfo::isMegamorphic() {
return times_rewritten >= MEGAMORPHIC_THRESHOLD; return times_rewritten >= IC_MEGAMORPHIC_THRESHOLD;
} }
} }
...@@ -33,6 +33,7 @@ class ICInfo; ...@@ -33,6 +33,7 @@ class ICInfo;
class ICInvalidator; class ICInvalidator;
#define IC_INVALDITION_HEADER_SIZE 6 #define IC_INVALDITION_HEADER_SIZE 6
#define IC_MEGAMORPHIC_THRESHOLD 100
struct ICSlotInfo { struct ICSlotInfo {
public: public:
...@@ -134,6 +135,10 @@ public: ...@@ -134,6 +135,10 @@ public:
bool shouldAttempt(); bool shouldAttempt();
bool isMegamorphic(); bool isMegamorphic();
// For use of the rewriter for computing aggressiveness:
int percentMegamorphic() const { return times_rewritten * 100 / IC_MEGAMORPHIC_THRESHOLD; }
int percentBackedoff() const { return retry_backoff; }
friend class ICSlotRewrite; friend class ICSlotRewrite;
}; };
......
...@@ -589,6 +589,17 @@ public: ...@@ -589,6 +589,17 @@ public:
static bool isLargeConstant(int64_t val) { return (val < (-1L << 31) || val >= (1L << 31) - 1); } static bool isLargeConstant(int64_t val) { return (val < (-1L << 31) || val >= (1L << 31) - 1); }
// The "aggressiveness" with which we should try to do this rewrite. It starts high, and decreases over time.
// The values are nominally in the range 0-100, with 0 being no aggressiveness and 100 being fully aggressive,
// but callers should be prepared to receive values from a larger range.
//
// It would be nice to have this be stateful so that we could support things like "Lower the aggressiveness for
// this sub-call and then increase it back afterwards".
int aggressiveness() {
const ICInfo* ic = rewrite->getICInfo();
return 100 - ic->percentBackedoff() - ic->percentMegamorphic();
}
friend class RewriterVar; friend class RewriterVar;
}; };
......
...@@ -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;
......
...@@ -986,7 +986,7 @@ Box* listNew(BoxedClass* cls, Box* container) { ...@@ -986,7 +986,7 @@ Box* listNew(BoxedClass* cls, Box* container) {
Box* listInit(BoxedList* self, Box* container) { Box* listInit(BoxedList* self, Box* container) {
assert(PyList_Check(self)); assert(PyList_Check(self));
if (container != None) { if (container) {
listIAdd(self, container); listIAdd(self, container);
} }
...@@ -1243,7 +1243,7 @@ void setupList() { ...@@ -1243,7 +1243,7 @@ void setupList() {
list_cls->giveAttr("__new__", list_cls->giveAttr("__new__",
new BoxedFunction(boxRTFunction((void*)listNew, UNKNOWN, 2, 1, false, false), { None })); new BoxedFunction(boxRTFunction((void*)listNew, UNKNOWN, 2, 1, false, false), { None }));
list_cls->giveAttr("__init__", list_cls->giveAttr("__init__",
new BoxedFunction(boxRTFunction((void*)listInit, UNKNOWN, 2, 1, false, false), { None })); new BoxedFunction(boxRTFunction((void*)listInit, UNKNOWN, 2, 1, false, false), { NULL }));
list_cls->giveAttr("count", new BoxedFunction(boxRTFunction((void*)listCount, BOXED_INT, 2))); list_cls->giveAttr("count", new BoxedFunction(boxRTFunction((void*)listCount, BOXED_INT, 2)));
list_cls->giveAttr( list_cls->giveAttr(
......
...@@ -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) {
...@@ -1474,6 +1499,23 @@ Box* getattrInternalEx(Box* obj, BoxedString* attr, GetattrRewriteArgs* rewrite_ ...@@ -1474,6 +1499,23 @@ Box* getattrInternalEx(Box* obj, BoxedString* attr, GetattrRewriteArgs* rewrite_
return NULL; return NULL;
} }
} else { } else {
if (unlikely(rewrite_args && rewrite_args->rewriter->aggressiveness() < 20)) {
class Helper {
public:
static Box* call(Box* obj, BoxedString* attr, bool cls_only) {
return getattrInternalGeneric(obj, attr, NULL, cls_only, false, NULL, NULL);
}
};
rewrite_args->out_rtn
= 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(cls_only, Location::forArg(2)));
rewrite_args->out_success = true;
rewrite_args->out_return_convention = GetattrRewriteArgs::NOEXC_POSSIBLE;
return Helper::call(obj, attr, cls_only);
}
return getattrInternalGeneric(obj, attr, rewrite_args, cls_only, for_call, bind_obj_out, r_bind_obj_out); return getattrInternalGeneric(obj, attr, rewrite_args, cls_only, for_call, bind_obj_out, r_bind_obj_out);
} }
} }
...@@ -1596,7 +1638,10 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew ...@@ -1596,7 +1638,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 +1743,7 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew ...@@ -1698,6 +1743,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);
...@@ -1714,6 +1760,22 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew ...@@ -1714,6 +1760,22 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew
if (!PyType_Check(obj)) { if (!PyType_Check(obj)) {
// Look up the val in the object's dictionary and if you find it, return it. // Look up the val in the object's dictionary and if you find it, return it.
if (unlikely(rewrite_args && !descr && obj->cls != instancemethod_cls
&& rewrite_args->rewriter->aggressiveness() < 40
&& attr->interned_state == SSTATE_INTERNED_IMMORTAL)) {
class Helper {
public:
static Box* call(Box* obj, BoxedString* attr) { return obj->getattr(attr); }
};
rewrite_args->out_rtn = rewrite_args->rewriter->call(
false, (void*)Helper::call, rewrite_args->obj,
rewrite_args->rewriter->loadConst((intptr_t)attr, Location::forArg(1)));
rewrite_args->out_success = true;
rewrite_args->out_return_convention = GetattrRewriteArgs::NOEXC_POSSIBLE;
return Helper::call(obj, attr);
}
Box* val; Box* val;
RewriterVar* r_val = NULL; RewriterVar* r_val = NULL;
if (rewrite_args) { if (rewrite_args) {
...@@ -1723,7 +1785,10 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew ...@@ -1723,7 +1785,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 +1798,7 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew ...@@ -1733,6 +1798,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 +1842,7 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew ...@@ -1776,6 +1842,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 +1858,7 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew ...@@ -1791,6 +1858,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 +1905,7 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew ...@@ -1837,6 +1905,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 +1919,7 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew ...@@ -1850,6 +1919,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 +1933,7 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew ...@@ -1863,6 +1933,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 +2010,29 @@ template <ExceptionStyle S> Box* _getattrEntry(Box* obj, BoxedString* attr, void ...@@ -1939,6 +2010,29 @@ template <ExceptionStyle S> Box* _getattrEntry(Box* obj, BoxedString* attr, void
ScopedStatTimer st(counter, 10); ScopedStatTimer st(counter, 10);
#endif #endif
if (unlikely(rewriter.get() && rewriter->aggressiveness() < 5)) {
RewriterVar* r_rtn = rewriter->call(true, (void*)_getattrEntry<S>, rewriter->getArg(0), rewriter->getArg(1),
rewriter->loadConst(0, Location::forArg(2)));
rewriter->commitReturning(r_rtn);
rewriter.reset(NULL);
}
// 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 +2045,37 @@ template <ExceptionStyle S> Box* _getattrEntry(Box* obj, BoxedString* attr, void ...@@ -1951,45 +2045,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;
} }
} 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); if (rewrite_args.out_return_convention == GetattrRewriteArgs::VALID_RETURN) {
} else { RewriterVar* r_rtn = rewrite_args.out_rtn;
rewriter->commitReturning(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);
}
rewriter->commitReturning(r_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 {
...@@ -2749,19 +2835,54 @@ Box* callattrInternal(Box* obj, BoxedString* attr, LookupScope scope, CallRewrit ...@@ -2749,19 +2835,54 @@ Box* callattrInternal(Box* obj, BoxedString* attr, LookupScope scope, CallRewrit
rewrite_args->func_guarded = true; rewrite_args->func_guarded = true;
} }
Box* rtn;
ArgPassSpec new_argspec ArgPassSpec new_argspec
= bindObjIntoArgs(bind_obj, r_bind_obj, rewrite_args, argspec, arg1, arg2, arg3, args, new_args); = bindObjIntoArgs(bind_obj, r_bind_obj, rewrite_args, argspec, arg1, arg2, arg3, args, new_args);
return runtimeCallInternal<S>(val, rewrite_args, new_argspec, arg1, arg2, arg3, new_args, keyword_names); argspec = new_argspec;
args = new_args;
} else { } else {
if (rewrite_args) { if (rewrite_args) {
rewrite_args->obj = r_val; rewrite_args->obj = r_val;
} }
}
Box* rtn = runtimeCallInternal<S>(val, rewrite_args, argspec, arg1, arg2, arg3, args, keyword_names); Box* rtn;
assert(rtn || (S == CAPI && PyErr_Occurred())); if (unlikely(rewrite_args && rewrite_args->rewriter->aggressiveness() < 50)) {
return rtn; class Helper {
public:
static Box* call(Box* val, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3, void** extra_args) {
Box** args = (Box**)extra_args[0];
const std::vector<BoxedString*>* keyword_names = (const std::vector<BoxedString*>*)extra_args[1];
return runtimeCallInternal<S>(val, NULL, argspec, arg1, arg2, arg3, args, keyword_names);
}
};
RewriterVar::SmallVector arg_vec;
arg_vec.push_back(rewrite_args->obj);
arg_vec.push_back(rewrite_args->rewriter->loadConst(argspec.asInt()));
arg_vec.push_back(argspec.totalPassed() >= 1 ? rewrite_args->arg1 : rewrite_args->rewriter->loadConst(0));
arg_vec.push_back(argspec.totalPassed() >= 2 ? rewrite_args->arg2 : rewrite_args->rewriter->loadConst(0));
arg_vec.push_back(argspec.totalPassed() >= 3 ? rewrite_args->arg3 : rewrite_args->rewriter->loadConst(0));
RewriterVar* arg_array = rewrite_args->rewriter->allocate(2);
arg_vec.push_back(arg_array);
if (argspec.totalPassed() >= 4)
arg_array->setAttr(0, rewrite_args->args);
else
arg_array->setAttr(0, rewrite_args->rewriter->loadConst(0));
if (argspec.num_keywords)
arg_array->setAttr(8, rewrite_args->rewriter->loadConst((intptr_t)keyword_names));
else
arg_array->setAttr(8, rewrite_args->rewriter->loadConst(0));
rewrite_args->out_rtn = rewrite_args->rewriter->call(true, (void*)Helper::call, arg_vec);
rewrite_args->out_success = true;
void* _args[2] = { args, const_cast<std::vector<BoxedString*>*>(keyword_names) };
return Helper::call(val, argspec, arg1, arg2, arg3, _args);
} }
return runtimeCallInternal<S>(val, rewrite_args, argspec, arg1, arg2, arg3, args, keyword_names);
} }
template <ExceptionStyle S> template <ExceptionStyle S>
...@@ -3122,8 +3243,8 @@ void rearrangeArguments(ParamReceiveSpec paramspec, const ParamNames* param_name ...@@ -3122,8 +3243,8 @@ void rearrangeArguments(ParamReceiveSpec paramspec, const ParamNames* param_name
rewrite_args = NULL; rewrite_args = NULL;
} }
if (paramspec.takes_varargs && argspec.num_args > paramspec.num_args + 3) { if (paramspec.takes_varargs && argspec.num_args > paramspec.num_args + 6) {
// We currently only handle up to 3 arguments into the varargs tuple // We currently only handle up to 6 arguments into the varargs tuple
rewrite_args = NULL; rewrite_args = NULL;
} }
...@@ -3217,19 +3338,18 @@ void rearrangeArguments(ParamReceiveSpec paramspec, const ParamNames* param_name ...@@ -3217,19 +3338,18 @@ void rearrangeArguments(ParamReceiveSpec paramspec, const ParamNames* param_name
if (varargs_size == 0) { if (varargs_size == 0) {
varargs_val = rewrite_args->rewriter->loadConst( varargs_val = rewrite_args->rewriter->loadConst(
(intptr_t)EmptyTuple, varargs_idx < 3 ? Location::forArg(varargs_idx) : Location::any()); (intptr_t)EmptyTuple, varargs_idx < 3 ? Location::forArg(varargs_idx) : Location::any());
} else if (varargs_size == 1) {
varargs_val
= rewrite_args->rewriter->call(false, (void*)BoxedTuple::create1, unused_positional_rvars[0]);
} else if (varargs_size == 2) {
varargs_val = rewrite_args->rewriter->call(false, (void*)BoxedTuple::create2,
unused_positional_rvars[0], unused_positional_rvars[1]);
} else if (varargs_size == 3) {
varargs_val
= rewrite_args->rewriter->call(false, (void*)BoxedTuple::create3, unused_positional_rvars[0],
unused_positional_rvars[1], unused_positional_rvars[2]);
} else { } else {
// This is too late to abort the rewrite (we should have checked this earlier) assert(varargs_size <= 6);
abort(); void* create_ptrs[] = {
NULL, //
(void*)BoxedTuple::create1, //
(void*)BoxedTuple::create2, //
(void*)BoxedTuple::create3, //
(void*)BoxedTuple::create4, //
(void*)BoxedTuple::create5, //
(void*)BoxedTuple::create6, //
};
varargs_val = rewrite_args->rewriter->call(false, create_ptrs[varargs_size], unused_positional_rvars);
} }
if (varargs_val) { if (varargs_val) {
...@@ -3525,6 +3645,17 @@ Box* callFunc(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ArgPassSpe ...@@ -3525,6 +3645,17 @@ Box* callFunc(BoxedFunctionBase* func, CallRewriteArgs* rewrite_args, ArgPassSpe
// TODO: we might not have a lot to gain by rewriting into createGenerator, but we could at least // TODO: we might not have a lot to gain by rewriting into createGenerator, but we could at least
// rewrite up to the call to it: // rewrite up to the call to it:
res = createGenerator(func, arg1, arg2, arg3, oargs); res = createGenerator(func, arg1, arg2, arg3, oargs);
if (rewrite_args) {
RewriterVar* r_arg1 = num_output_args >= 1 ? rewrite_args->arg1 : rewrite_args->rewriter->loadConst(0);
RewriterVar* r_arg2 = num_output_args >= 2 ? rewrite_args->arg2 : rewrite_args->rewriter->loadConst(0);
RewriterVar* r_arg3 = num_output_args >= 3 ? rewrite_args->arg3 : rewrite_args->rewriter->loadConst(0);
RewriterVar* r_args = num_output_args >= 4 ? rewrite_args->args : rewrite_args->rewriter->loadConst(0);
rewrite_args->out_rtn = rewrite_args->rewriter->call(true, (void*)createGenerator, rewrite_args->obj,
r_arg1, r_arg2, r_arg3, r_args);
rewrite_args->out_success = true;
}
} else { } else {
res = callCLFunc<S>(f, rewrite_args, num_output_args, closure, NULL, func->globals, arg1, arg2, arg3, oargs); res = callCLFunc<S>(f, rewrite_args, num_output_args, closure, NULL, func->globals, arg1, arg2, arg3, oargs);
} }
......
...@@ -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 {
......
...@@ -557,6 +557,18 @@ public: ...@@ -557,6 +557,18 @@ public:
assert(gc::isValidGCObject(rtn->elts[i])); assert(gc::isValidGCObject(rtn->elts[i]));
return rtn; return rtn;
} }
static BoxedTuple* create6(Box* elt0, Box* elt1, Box* elt2, Box* elt3, Box* elt4, Box* elt5) {
BoxedTuple* rtn = new (6) BoxedTuple();
rtn->elts[0] = elt0;
rtn->elts[1] = elt1;
rtn->elts[2] = elt2;
rtn->elts[3] = elt3;
rtn->elts[4] = elt4;
rtn->elts[5] = elt5;
for (int i = 0; i < rtn->size(); i++)
assert(gc::isValidGCObject(rtn->elts[i]));
return rtn;
}
static BoxedTuple* create(std::initializer_list<Box*> members) { static BoxedTuple* create(std::initializer_list<Box*> members) {
auto rtn = new (members.size()) BoxedTuple(members); auto rtn = new (members.size()) BoxedTuple(members);
......
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