Commit a4b0a153 authored by Marius Wachtler's avatar Marius Wachtler

Merge pull request #976 from undingen/instance_setattr

rewrite instance_setattro
parents 5472b5e0 26cbd0d2
......@@ -46,6 +46,14 @@ static Box* classLookup(BoxedClassobj* cls, BoxedString* attr, GetattrRewriteArg
return r;
}
if (cls->bases == EmptyTuple) {
if (rewrite_args && rewrite_args->isSuccessful()) {
rewrite_args->obj->addAttrGuard(offsetof(BoxedClassobj, bases), (uint64_t)EmptyTuple);
rewrite_args->assertReturnConvention(ReturnConvention::NO_RETURN);
}
return NULL;
}
if (rewrite_args) {
if (rewrite_args->isSuccessful()) {
rewrite_args->getReturn(); // just to make the asserts happy
......@@ -489,7 +497,9 @@ Box* instanceGetattroInternal(Box* cls, Box* _attr, GetattrRewriteArgs* rewrite_
template Box* instanceGetattroInternal<CAPI>(Box*, Box*, GetattrRewriteArgs*) noexcept;
template Box* instanceGetattroInternal<CXX>(Box*, Box*, GetattrRewriteArgs*);
Box* instanceSetattr(Box* _inst, Box* _attr, Box* value) {
Box* instanceSetattroInternal(Box* _inst, Box* _attr, Box* value, SetattrRewriteArgs* rewrite_args) {
STAT_TIMER(t0, "us_timer_instance_setattro", 0);
RELEASE_ASSERT(_inst->cls == instance_cls, "");
BoxedInstance* inst = static_cast<BoxedInstance*>(_inst);
......@@ -513,15 +523,43 @@ Box* instanceSetattr(Box* _inst, Box* _attr, Box* value) {
}
static BoxedString* setattr_str = internStringImmortal("__setattr__");
Box* setattr = classLookup(inst->inst_cls, setattr_str);
if (setattr) {
setattr = processDescriptor(setattr, inst, inst->inst_cls);
return runtimeCall(setattr, ArgPassSpec(2), _attr, value, NULL, NULL, NULL);
if (rewrite_args) {
RewriterVar* inst_r = rewrite_args->obj->getAttr(offsetof(BoxedInstance, inst_cls));
inst_r->addGuard((uint64_t)inst->inst_cls);
GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, inst_r,
rewrite_args->rewriter->getReturnDestination());
Box* setattr = classLookup<REWRITABLE>(inst->inst_cls, setattr_str, &grewrite_args);
if (!grewrite_args.isSuccessful()) {
assert(!rewrite_args->out_success);
rewrite_args = NULL;
}
if (setattr) {
setattr = processDescriptor(setattr, inst, inst->inst_cls);
return runtimeCall(setattr, ArgPassSpec(2), _attr, value, NULL, NULL, NULL);
}
if (rewrite_args)
grewrite_args.assertReturnConvention(ReturnConvention::NO_RETURN);
_inst->setattr(attr, value, rewrite_args);
return None;
} else {
Box* setattr = classLookup(inst->inst_cls, setattr_str);
if (setattr) {
setattr = processDescriptor(setattr, inst, inst->inst_cls);
return runtimeCall(setattr, ArgPassSpec(2), _attr, value, NULL, NULL, NULL);
}
_inst->setattr(attr, value, NULL);
return None;
}
}
_inst->setattr(attr, value, NULL);
return None;
Box* instanceSetattr(Box* _inst, Box* _attr, Box* value) {
return instanceSetattroInternal(_inst, _attr, value, NULL);
}
Box* instanceDelattr(Box* _inst, Box* _attr) {
......@@ -552,7 +590,7 @@ Box* instanceDelattr(Box* _inst, Box* _attr) {
return None;
}
static int instance_setattro(Box* cls, Box* attr, Box* value) noexcept {
int instance_setattro(Box* cls, Box* attr, Box* value) noexcept {
try {
if (value) {
instanceSetattr(cls, attr, value);
......
......@@ -85,9 +85,11 @@ public:
};
Box* instance_getattro(Box* cls, Box* attr) noexcept;
int instance_setattro(Box* cls, Box* attr, Box* value) noexcept;
class GetattrRewriteArgs;
template <ExceptionStyle S>
Box* instanceGetattroInternal(Box* self, Box* attr, GetattrRewriteArgs* rewrite_args) noexcept(S == CAPI);
Box* instanceSetattroInternal(Box* self, Box* attr, Box* val, SetattrRewriteArgs* rewrite_args);
}
#endif
......@@ -2429,12 +2429,22 @@ extern "C" void setattr(Box* obj, BoxedString* attr, Box* attr_val) {
r_cls->addAttrGuard(offsetof(BoxedClass, tp_setattro), (intptr_t)tp_setattro);
}
// Note: setattr will only be retrieved if we think it will be profitable to try calling that as opposed to
// the tp_setattr function pointer.
Box* setattr = NULL;
RewriterVar* r_setattr;
if (tp_setattro != PyObject_GenericSetAttr) {
if (tp_setattro == instance_setattro) {
if (rewriter.get()) {
SetattrRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0), rewriter->getArg(2));
instanceSetattroInternal(obj, attr, attr_val, &rewrite_args);
if (rewrite_args.out_success)
rewriter->commit();
} else
instanceSetattroInternal(obj, attr, attr_val, NULL);
return;
} else if (tp_setattro != PyObject_GenericSetAttr) {
static BoxedString* setattr_str = internStringImmortal("__setattr__");
if (rewriter.get()) {
GetattrRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0)->getAttr(offsetof(Box, cls)),
......
......@@ -372,6 +372,8 @@ extern "C" Box* tupleNew(Box* _cls, BoxedTuple* args, BoxedDict* kwargs) {
return BoxedTuple::create(elts.size(), &elts[0], cls);
} else {
if (cls == tuple_cls)
return EmptyTuple;
return BoxedTuple::create(0, cls);
}
}
......
......@@ -492,3 +492,22 @@ try:
except:
print sys.exc_info()[0].__name__, sys.exc_info()[1]
s1 = 0
class C():
pass
class D():
def __setattr__(self, a, v):
global s1
s1 += v
o = C()
s2 = 0
for i in range(500):
o.a = 1
s2 += o.a
if i == 100:
C.__bases__ = (D,)
if i == 150:
C.__bases__ = tuple()
print s1, s2
......@@ -30,3 +30,11 @@ test(Test())
del Test.__setattr__
for i in xrange(100):
test(Test())
class Old():
pass
old = Old()
for i in xrange(1000):
old.a = i
assert old.a == i
......@@ -27,6 +27,8 @@ print (2,) < (2,)
print (2,) < (2, 3)
print (3,) < (2, 3)
print () is (), () is tuple(), tuple() is tuple()
print
class T(object):
......
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