Commit 87d01381 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Allow non-string object attributes

by converting to our DICT_BACKED hidden class strategy.
parent 4dde3519
......@@ -527,10 +527,13 @@ public:
llvm::iterator_range<BoxIterator> pyElements();
// For instances with hc attrs:
size_t getHCAttrsOffset();
HCAttrs* getHCAttrsPtr();
void setDict(BoxedDict* d);
void setDictBacked(Box* d);
// For instances with dict attrs:
BoxedDict* getDict();
void setDict(BoxedDict* d);
void setattr(BoxedString* attr, Box* val, SetattrRewriteArgs* rewrite_args);
......
......@@ -602,6 +602,7 @@ static void orderFinalizers() {
std::vector<Box*> finalizer_marked;
for (Box* obj : objects_with_ordered_finalizers) {
GC_TRACE_LOG("%p has an ordered finalizer\n", obj);
GCAllocation* al = GCAllocation::fromUserData(obj);
// We are only interested in object with finalizers that need to be garbage-collected.
......
......@@ -28,14 +28,6 @@
#define GC_KEEP_ALIVE(t) asm volatile("" : : "X"(t))
#define TRACE_GC_MARKING 0
#if TRACE_GC_MARKING
extern FILE* trace_fp;
#define GC_TRACE_LOG(...) fprintf(pyston::gc::trace_fp, __VA_ARGS__)
#else
#define GC_TRACE_LOG(...)
#endif
struct _PyWeakReference;
typedef struct _PyWeakReference PyWeakReference;
......@@ -45,6 +37,14 @@ class Box;
namespace gc {
class GCVisitable;
#define TRACE_GC_MARKING 0
#if TRACE_GC_MARKING
extern FILE* trace_fp;
#define GC_TRACE_LOG(...) fprintf(pyston::gc::trace_fp, __VA_ARGS__)
#else
#define GC_TRACE_LOG(...)
#endif
}
namespace threading {
......
......@@ -598,7 +598,7 @@ Box* setattrFunc(Box* obj, Box* _str, Box* value) {
_str = coerceUnicodeToStr<CXX>(_str);
if (_str->cls != str_cls) {
raiseExcHelper(TypeError, "setattr(): attribute name must be string");
raiseExcHelper(TypeError, "attribute name must be string, not '%s'", _str->cls->tp_name);
}
BoxedString* str = static_cast<BoxedString*>(_str);
......
......@@ -996,12 +996,10 @@ Box* typeLookup(BoxedClass* cls, BoxedString* attr, GetattrRewriteArgs* rewrite_
rewrite_args->obj_shape_guarded = true;
}
val = base->getattr(attr, rewrite_args);
assert(rewrite_args->out_success);
if (val)
return val;
}
assert(rewrite_args->out_success);
assert(!rewrite_args->out_rtn);
rewrite_args->out_return_convention = GetattrRewriteArgs::NO_RETURN;
return NULL;
......
......@@ -1398,6 +1398,20 @@ static Box* typeSubDict(Box* obj, void* context) {
abort();
}
void Box::setDictBacked(Box* val) {
assert(this->cls->instancesHaveHCAttrs());
RELEASE_ASSERT(val->cls == dict_cls || val->cls == attrwrapper_cls, "");
auto new_attr_list = (HCAttrs::AttrList*)gc_alloc(sizeof(HCAttrs::AttrList) + sizeof(Box*), gc::GCKind::PRECISE);
new_attr_list->attrs[0] = val;
HCAttrs* hcattrs = this->getHCAttrsPtr();
hcattrs->hcls = HiddenClass::dict_backed;
hcattrs->attr_list = new_attr_list;
}
static void typeSubSetDict(Box* obj, Box* val, void* context) {
if (obj->cls->instancesHaveDictAttrs()) {
RELEASE_ASSERT(val->cls == dict_cls, "");
......@@ -1406,16 +1420,7 @@ static void typeSubSetDict(Box* obj, Box* val, void* context) {
}
if (obj->cls->instancesHaveHCAttrs()) {
RELEASE_ASSERT(val->cls == dict_cls || val->cls == attrwrapper_cls, "");
auto new_attr_list
= (HCAttrs::AttrList*)gc_alloc(sizeof(HCAttrs::AttrList) + sizeof(Box*), gc::GCKind::PRECISE);
new_attr_list->attrs[0] = val;
HCAttrs* hcattrs = obj->getHCAttrsPtr();
hcattrs->hcls = HiddenClass::dict_backed;
hcattrs->attr_list = new_attr_list;
obj->setDictBacked(val);
return;
}
......@@ -2218,6 +2223,28 @@ class AttrWrapper : public Box {
private:
Box* b;
void convertToDictBacked() {
HCAttrs* attrs = this->b->getHCAttrsPtr();
if (attrs->hcls->type == HiddenClass::DICT_BACKED)
return;
BoxedDict* d = new BoxedDict();
RELEASE_ASSERT(attrs->hcls->type == HiddenClass::NORMAL || attrs->hcls->type == HiddenClass::SINGLETON, "");
for (const auto& p : attrs->hcls->getStrAttrOffsets()) {
d->d[p.first] = attrs->attr_list->attrs[p.second];
}
b->setDictBacked(d);
}
bool isDictBacked() { return b->getHCAttrsPtr()->hcls->type == HiddenClass::DICT_BACKED; }
Box* getDictBacking() {
assert(isDictBacked());
return b->getHCAttrsPtr()->attr_list->attrs[0];
}
public:
AttrWrapper(Box* b) : b(b) {
assert(b->cls->instancesHaveHCAttrs());
......@@ -2246,9 +2273,16 @@ public:
RELEASE_ASSERT(_self->cls == attrwrapper_cls, "");
AttrWrapper* self = static_cast<AttrWrapper*>(_self);
_key = coerceUnicodeToStr<CXX>(_key);
if (_key->cls != str_cls)
self->convertToDictBacked();
RELEASE_ASSERT(_key->cls == str_cls, "");
if (self->isDictBacked()) {
static BoxedString* setitem_str = internStringImmortal("__setitem__");
return callattrInternal<CXX>(self->getDictBacking(), setitem_str, LookupScope::CLASS_ONLY, NULL,
ArgPassSpec(2), _key, value, NULL, NULL, NULL);
}
assert(_key->cls == str_cls);
BoxedString* key = static_cast<BoxedString*>(_key);
internStringMortalInplace(key);
......@@ -2276,9 +2310,16 @@ public:
RELEASE_ASSERT(_self->cls == attrwrapper_cls, "");
AttrWrapper* self = static_cast<AttrWrapper*>(_self);
_key = coerceUnicodeToStr<CXX>(_key);
if (_key->cls != str_cls)
self->convertToDictBacked();
RELEASE_ASSERT(_key->cls == str_cls, "");
if (self->isDictBacked()) {
static BoxedString* setdefault_str = internStringImmortal("setdefault");
return callattrInternal<CXX>(self->getDictBacking(), setdefault_str, LookupScope::CLASS_ONLY, NULL,
ArgPassSpec(2), _key, value, NULL, NULL, NULL);
}
assert(_key->cls == str_cls);
BoxedString* key = static_cast<BoxedString*>(_key);
internStringMortalInplace(key);
......@@ -2313,7 +2354,7 @@ public:
if (S == CAPI && !_key)
return NULL;
RELEASE_ASSERT(_key->cls == str_cls, "%s", _key->cls->tp_name);
RELEASE_ASSERT(_key->cls == str_cls, "");
BoxedString* key = static_cast<BoxedString*>(_key);
internStringMortalInplace(key);
......@@ -2354,7 +2395,7 @@ public:
_key = coerceUnicodeToStr<CXX>(_key);
RELEASE_ASSERT(_key->cls == str_cls, "%s", _key->cls->tp_name);
RELEASE_ASSERT(_key->cls == str_cls, "");
BoxedString* key = static_cast<BoxedString*>(_key);
internStringMortalInplace(key);
......@@ -2559,6 +2600,12 @@ public:
RELEASE_ASSERT(_self->cls == attrwrapper_cls, "");
AttrWrapper* self = static_cast<AttrWrapper*>(_self);
if (self->isDictBacked()) {
static BoxedString* iter_str = internStringImmortal("__iter__");
return callattrInternal<CXX>(self->getDictBacking(), iter_str, LookupScope::CLASS_ONLY, NULL,
ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL);
}
return new AttrWrapperIter(self);
}
......
......@@ -123,3 +123,24 @@ while True:
except StopIteration:
break
print sorted(l)
c = C1()
print sorted(c.__dict__.items())
# setattr() converts the attr name to a string:
setattr(c, u'a', 1)
print sorted(c.__dict__.items())
# directly setting on the dict does not:
c.__dict__[u'b'] = 2
print sorted(c.__dict__.items())
c.__dict__.update({u'c':3})
print sorted(c.__dict__.items())
# Can't set non-string-attrs with setattr, but can via dict:
try:
setattr(c, 1, 1)
assert 0
except TypeError as e:
print e
print sorted(c.__dict__.items())
c.__dict__[5] = 2
print sorted(c.__dict__.items())
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