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 ...@@ -46,6 +46,14 @@ static Box* classLookup(BoxedClassobj* cls, BoxedString* attr, GetattrRewriteArg
return r; 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) {
if (rewrite_args->isSuccessful()) { if (rewrite_args->isSuccessful()) {
rewrite_args->getReturn(); // just to make the asserts happy rewrite_args->getReturn(); // just to make the asserts happy
...@@ -489,7 +497,9 @@ Box* instanceGetattroInternal(Box* cls, Box* _attr, GetattrRewriteArgs* rewrite_ ...@@ -489,7 +497,9 @@ Box* instanceGetattroInternal(Box* cls, Box* _attr, GetattrRewriteArgs* rewrite_
template Box* instanceGetattroInternal<CAPI>(Box*, Box*, GetattrRewriteArgs*) noexcept; template Box* instanceGetattroInternal<CAPI>(Box*, Box*, GetattrRewriteArgs*) noexcept;
template Box* instanceGetattroInternal<CXX>(Box*, Box*, GetattrRewriteArgs*); 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, ""); RELEASE_ASSERT(_inst->cls == instance_cls, "");
BoxedInstance* inst = static_cast<BoxedInstance*>(_inst); BoxedInstance* inst = static_cast<BoxedInstance*>(_inst);
...@@ -513,8 +523,31 @@ Box* instanceSetattr(Box* _inst, Box* _attr, Box* value) { ...@@ -513,8 +523,31 @@ Box* instanceSetattr(Box* _inst, Box* _attr, Box* value) {
} }
static BoxedString* setattr_str = internStringImmortal("__setattr__"); static BoxedString* setattr_str = internStringImmortal("__setattr__");
Box* setattr = classLookup(inst->inst_cls, setattr_str);
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) { if (setattr) {
setattr = processDescriptor(setattr, inst, inst->inst_cls); setattr = processDescriptor(setattr, inst, inst->inst_cls);
return runtimeCall(setattr, ArgPassSpec(2), _attr, value, NULL, NULL, NULL); return runtimeCall(setattr, ArgPassSpec(2), _attr, value, NULL, NULL, NULL);
...@@ -522,6 +555,11 @@ Box* instanceSetattr(Box* _inst, Box* _attr, Box* value) { ...@@ -522,6 +555,11 @@ Box* instanceSetattr(Box* _inst, Box* _attr, Box* value) {
_inst->setattr(attr, value, NULL); _inst->setattr(attr, value, NULL);
return None; return None;
}
}
Box* instanceSetattr(Box* _inst, Box* _attr, Box* value) {
return instanceSetattroInternal(_inst, _attr, value, NULL);
} }
Box* instanceDelattr(Box* _inst, Box* _attr) { Box* instanceDelattr(Box* _inst, Box* _attr) {
...@@ -552,7 +590,7 @@ Box* instanceDelattr(Box* _inst, Box* _attr) { ...@@ -552,7 +590,7 @@ Box* instanceDelattr(Box* _inst, Box* _attr) {
return None; return None;
} }
static int instance_setattro(Box* cls, Box* attr, Box* value) noexcept { int instance_setattro(Box* cls, Box* attr, Box* value) noexcept {
try { try {
if (value) { if (value) {
instanceSetattr(cls, attr, value); instanceSetattr(cls, attr, value);
......
...@@ -85,9 +85,11 @@ public: ...@@ -85,9 +85,11 @@ public:
}; };
Box* instance_getattro(Box* cls, Box* attr) noexcept; Box* instance_getattro(Box* cls, Box* attr) noexcept;
int instance_setattro(Box* cls, Box* attr, Box* value) noexcept;
class GetattrRewriteArgs; class GetattrRewriteArgs;
template <ExceptionStyle S> template <ExceptionStyle S>
Box* instanceGetattroInternal(Box* self, Box* attr, GetattrRewriteArgs* rewrite_args) noexcept(S == CAPI); Box* instanceGetattroInternal(Box* self, Box* attr, GetattrRewriteArgs* rewrite_args) noexcept(S == CAPI);
Box* instanceSetattroInternal(Box* self, Box* attr, Box* val, SetattrRewriteArgs* rewrite_args);
} }
#endif #endif
...@@ -2429,12 +2429,22 @@ extern "C" void setattr(Box* obj, BoxedString* attr, Box* attr_val) { ...@@ -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); 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 // 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. // the tp_setattr function pointer.
Box* setattr = NULL; Box* setattr = NULL;
RewriterVar* r_setattr; 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__"); static BoxedString* setattr_str = internStringImmortal("__setattr__");
if (rewriter.get()) { if (rewriter.get()) {
GetattrRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0)->getAttr(offsetof(Box, cls)), 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) { ...@@ -372,6 +372,8 @@ extern "C" Box* tupleNew(Box* _cls, BoxedTuple* args, BoxedDict* kwargs) {
return BoxedTuple::create(elts.size(), &elts[0], cls); return BoxedTuple::create(elts.size(), &elts[0], cls);
} else { } else {
if (cls == tuple_cls)
return EmptyTuple;
return BoxedTuple::create(0, cls); return BoxedTuple::create(0, cls);
} }
} }
......
...@@ -492,3 +492,22 @@ try: ...@@ -492,3 +492,22 @@ try:
except: except:
print sys.exc_info()[0].__name__, sys.exc_info()[1] 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()) ...@@ -30,3 +30,11 @@ test(Test())
del Test.__setattr__ del Test.__setattr__
for i in xrange(100): for i in xrange(100):
test(Test()) 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,) ...@@ -27,6 +27,8 @@ print (2,) < (2,)
print (2,) < (2, 3) print (2,) < (2, 3)
print (3,) < (2, 3) print (3,) < (2, 3)
print () is (), () is tuple(), tuple() is tuple()
print print
class T(object): 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