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: ...@@ -527,10 +527,13 @@ public:
llvm::iterator_range<BoxIterator> pyElements(); llvm::iterator_range<BoxIterator> pyElements();
// For instances with hc attrs:
size_t getHCAttrsOffset(); size_t getHCAttrsOffset();
HCAttrs* getHCAttrsPtr(); HCAttrs* getHCAttrsPtr();
void setDict(BoxedDict* d); void setDictBacked(Box* d);
// For instances with dict attrs:
BoxedDict* getDict(); BoxedDict* getDict();
void setDict(BoxedDict* d);
void setattr(BoxedString* attr, Box* val, SetattrRewriteArgs* rewrite_args); void setattr(BoxedString* attr, Box* val, SetattrRewriteArgs* rewrite_args);
......
...@@ -602,6 +602,7 @@ static void orderFinalizers() { ...@@ -602,6 +602,7 @@ static void orderFinalizers() {
std::vector<Box*> finalizer_marked; std::vector<Box*> finalizer_marked;
for (Box* obj : objects_with_ordered_finalizers) { for (Box* obj : objects_with_ordered_finalizers) {
GC_TRACE_LOG("%p has an ordered finalizer\n", obj);
GCAllocation* al = GCAllocation::fromUserData(obj); GCAllocation* al = GCAllocation::fromUserData(obj);
// We are only interested in object with finalizers that need to be garbage-collected. // We are only interested in object with finalizers that need to be garbage-collected.
......
...@@ -28,14 +28,6 @@ ...@@ -28,14 +28,6 @@
#define GC_KEEP_ALIVE(t) asm volatile("" : : "X"(t)) #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; struct _PyWeakReference;
typedef struct _PyWeakReference PyWeakReference; typedef struct _PyWeakReference PyWeakReference;
...@@ -45,6 +37,14 @@ class Box; ...@@ -45,6 +37,14 @@ class Box;
namespace gc { namespace gc {
class GCVisitable; 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 { namespace threading {
......
...@@ -598,7 +598,7 @@ Box* setattrFunc(Box* obj, Box* _str, Box* value) { ...@@ -598,7 +598,7 @@ Box* setattrFunc(Box* obj, Box* _str, Box* value) {
_str = coerceUnicodeToStr<CXX>(_str); _str = coerceUnicodeToStr<CXX>(_str);
if (_str->cls != str_cls) { 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); BoxedString* str = static_cast<BoxedString*>(_str);
......
...@@ -996,12 +996,10 @@ Box* typeLookup(BoxedClass* cls, BoxedString* attr, GetattrRewriteArgs* rewrite_ ...@@ -996,12 +996,10 @@ Box* typeLookup(BoxedClass* cls, BoxedString* attr, GetattrRewriteArgs* rewrite_
rewrite_args->obj_shape_guarded = true; rewrite_args->obj_shape_guarded = true;
} }
val = base->getattr(attr, rewrite_args); val = base->getattr(attr, rewrite_args);
assert(rewrite_args->out_success);
if (val) if (val)
return val; return val;
} }
assert(rewrite_args->out_success);
assert(!rewrite_args->out_rtn); assert(!rewrite_args->out_rtn);
rewrite_args->out_return_convention = GetattrRewriteArgs::NO_RETURN; rewrite_args->out_return_convention = GetattrRewriteArgs::NO_RETURN;
return NULL; return NULL;
......
...@@ -1398,6 +1398,20 @@ static Box* typeSubDict(Box* obj, void* context) { ...@@ -1398,6 +1398,20 @@ static Box* typeSubDict(Box* obj, void* context) {
abort(); 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) { static void typeSubSetDict(Box* obj, Box* val, void* context) {
if (obj->cls->instancesHaveDictAttrs()) { if (obj->cls->instancesHaveDictAttrs()) {
RELEASE_ASSERT(val->cls == dict_cls, ""); RELEASE_ASSERT(val->cls == dict_cls, "");
...@@ -1406,16 +1420,7 @@ static void typeSubSetDict(Box* obj, Box* val, void* context) { ...@@ -1406,16 +1420,7 @@ static void typeSubSetDict(Box* obj, Box* val, void* context) {
} }
if (obj->cls->instancesHaveHCAttrs()) { if (obj->cls->instancesHaveHCAttrs()) {
RELEASE_ASSERT(val->cls == dict_cls || val->cls == attrwrapper_cls, ""); obj->setDictBacked(val);
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;
return; return;
} }
...@@ -2218,6 +2223,28 @@ class AttrWrapper : public Box { ...@@ -2218,6 +2223,28 @@ class AttrWrapper : public Box {
private: private:
Box* b; 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: public:
AttrWrapper(Box* b) : b(b) { AttrWrapper(Box* b) : b(b) {
assert(b->cls->instancesHaveHCAttrs()); assert(b->cls->instancesHaveHCAttrs());
...@@ -2246,9 +2273,16 @@ public: ...@@ -2246,9 +2273,16 @@ public:
RELEASE_ASSERT(_self->cls == attrwrapper_cls, ""); RELEASE_ASSERT(_self->cls == attrwrapper_cls, "");
AttrWrapper* self = static_cast<AttrWrapper*>(_self); 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); BoxedString* key = static_cast<BoxedString*>(_key);
internStringMortalInplace(key); internStringMortalInplace(key);
...@@ -2276,9 +2310,16 @@ public: ...@@ -2276,9 +2310,16 @@ public:
RELEASE_ASSERT(_self->cls == attrwrapper_cls, ""); RELEASE_ASSERT(_self->cls == attrwrapper_cls, "");
AttrWrapper* self = static_cast<AttrWrapper*>(_self); 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); BoxedString* key = static_cast<BoxedString*>(_key);
internStringMortalInplace(key); internStringMortalInplace(key);
...@@ -2313,7 +2354,7 @@ public: ...@@ -2313,7 +2354,7 @@ public:
if (S == CAPI && !_key) if (S == CAPI && !_key)
return NULL; 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); BoxedString* key = static_cast<BoxedString*>(_key);
internStringMortalInplace(key); internStringMortalInplace(key);
...@@ -2354,7 +2395,7 @@ public: ...@@ -2354,7 +2395,7 @@ public:
_key = coerceUnicodeToStr<CXX>(_key); _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); BoxedString* key = static_cast<BoxedString*>(_key);
internStringMortalInplace(key); internStringMortalInplace(key);
...@@ -2559,6 +2600,12 @@ public: ...@@ -2559,6 +2600,12 @@ public:
RELEASE_ASSERT(_self->cls == attrwrapper_cls, ""); RELEASE_ASSERT(_self->cls == attrwrapper_cls, "");
AttrWrapper* self = static_cast<AttrWrapper*>(_self); 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); return new AttrWrapperIter(self);
} }
......
...@@ -123,3 +123,24 @@ while True: ...@@ -123,3 +123,24 @@ while True:
except StopIteration: except StopIteration:
break break
print sorted(l) 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