Commit 933834be authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #510 from kmod/singleton_hcls

Singleton hcls storage strategy
parents 9030ec59 4ca839f9
...@@ -2717,13 +2717,14 @@ extern "C" int PyType_Ready(PyTypeObject* cls) noexcept { ...@@ -2717,13 +2717,14 @@ extern "C" int PyType_Ready(PyTypeObject* cls) noexcept {
RELEASE_ASSERT(cls->tp_del == NULL, ""); RELEASE_ASSERT(cls->tp_del == NULL, "");
RELEASE_ASSERT(cls->tp_version_tag == 0, ""); RELEASE_ASSERT(cls->tp_version_tag == 0, "");
// I think it is safe to ignore these for for now: // I think it is safe to ignore these for for now:
// RELEASE_ASSERT(cls->tp_weaklistoffset == 0, ""); // RELEASE_ASSERT(cls->tp_weaklistoffset == 0, "");
// RELEASE_ASSERT(cls->tp_traverse == NULL, ""); // RELEASE_ASSERT(cls->tp_traverse == NULL, "");
// RELEASE_ASSERT(cls->tp_clear == NULL, ""); // RELEASE_ASSERT(cls->tp_clear == NULL, "");
assert(cls->attrs.hcls == NULL);
new (&cls->attrs) HCAttrs(HiddenClass::makeSingleton());
#define INITIALIZE(a) new (&(a)) decltype(a) #define INITIALIZE(a) new (&(a)) decltype(a)
INITIALIZE(cls->attrs);
INITIALIZE(cls->dependent_icgetattrs); INITIALIZE(cls->dependent_icgetattrs);
#undef INITIALIZE #undef INITIALIZE
......
...@@ -418,7 +418,7 @@ public: ...@@ -418,7 +418,7 @@ public:
HiddenClass* hcls; HiddenClass* hcls;
AttrList* attr_list; AttrList* attr_list;
HCAttrs() : hcls(root_hcls), attr_list(nullptr) {} HCAttrs(HiddenClass* hcls = root_hcls) : hcls(hcls), attr_list(nullptr) {}
}; };
class BoxedDict; class BoxedDict;
...@@ -428,11 +428,8 @@ class Box { ...@@ -428,11 +428,8 @@ class Box {
private: private:
BoxedDict** getDictPtr(); BoxedDict** getDictPtr();
// Adds a new attribute to a HCAttrs-backed object. Must pass in the new hidden class object // Appends a new value to the hcattrs array.
// which must be the same as the current hidden class but with the new attribute at the end. void appendNewHCAttr(Box* val, SetattrRewriteArgs* rewrite_args);
// Swaps the hidden class, reallocates and copies and updates the attribute array.
// The value of the current hidden class should be guarded before calling this.
void addNewHCAttr(HiddenClass* new_hcls, Box* val, SetattrRewriteArgs* rewrite_args);
public: public:
// Add a no-op constructor to make sure that we don't zero-initialize cls // Add a no-op constructor to make sure that we don't zero-initialize cls
......
...@@ -208,7 +208,7 @@ struct HeapStatistics { ...@@ -208,7 +208,7 @@ struct HeapStatistics {
TypeStats total; TypeStats total;
HeapStatistics(bool collect_cls_stats, bool collect_hcls_stats) HeapStatistics(bool collect_cls_stats, bool collect_hcls_stats)
: collect_cls_stats(collect_cls_stats), collect_hcls_stats(collect_hcls_stats) { : collect_cls_stats(collect_cls_stats), collect_hcls_stats(collect_hcls_stats), num_hcls_by_attrs_exceed(0) {
memset(num_hcls_by_attrs, 0, sizeof(num_hcls_by_attrs)); memset(num_hcls_by_attrs, 0, sizeof(num_hcls_by_attrs));
} }
}; };
...@@ -233,6 +233,10 @@ void addStatistic(HeapStatistics* stats, GCAllocation* al, int nbytes) { ...@@ -233,6 +233,10 @@ void addStatistic(HeapStatistics* stats, GCAllocation* al, int nbytes) {
Box* b = (Box*)al->user_data; Box* b = (Box*)al->user_data;
if (b->cls->instancesHaveHCAttrs()) { if (b->cls->instancesHaveHCAttrs()) {
HCAttrs* attrs = b->getHCAttrsPtr(); HCAttrs* attrs = b->getHCAttrsPtr();
if (attrs->hcls->attributeArraySize() >= 20) {
printf("%s object has %d attributes\n", b->cls->tp_name, attrs->hcls->attributeArraySize());
}
stats->hcls_uses[attrs->hcls]++; stats->hcls_uses[attrs->hcls]++;
} }
} }
......
...@@ -228,7 +228,6 @@ extern "C" int PyDict_SetItem(PyObject* mp, PyObject* _key, PyObject* _item) noe ...@@ -228,7 +228,6 @@ extern "C" int PyDict_SetItem(PyObject* mp, PyObject* _key, PyObject* _item) noe
Box* item = static_cast<Box*>(_item); Box* item = static_cast<Box*>(_item);
try { try {
// TODO should demote GIL?
setitem(b, key, item); setitem(b, key, item);
} catch (ExcInfo e) { } catch (ExcInfo e) {
abort(); abort();
...@@ -249,6 +248,16 @@ extern "C" int PyDict_SetItemString(PyObject* mp, const char* key, PyObject* ite ...@@ -249,6 +248,16 @@ extern "C" int PyDict_SetItemString(PyObject* mp, const char* key, PyObject* ite
extern "C" PyObject* PyDict_GetItem(PyObject* dict, PyObject* key) noexcept { extern "C" PyObject* PyDict_GetItem(PyObject* dict, PyObject* key) noexcept {
ASSERT(isSubclass(dict->cls, dict_cls) || dict->cls == attrwrapper_cls, "%s", getTypeName(dict)); ASSERT(isSubclass(dict->cls, dict_cls) || dict->cls == attrwrapper_cls, "%s", getTypeName(dict));
if (isSubclass(dict->cls, dict_cls)) {
BoxedDict* d = static_cast<BoxedDict*>(dict);
auto it = d->d.find(key);
if (it != d->d.end())
return it->second;
return NULL;
}
// This path doesn't exist in CPython; we have it to support extension modules that do
// something along the lines of PyDict_GetItem(PyModule_GetDict()):
try { try {
return getitem(dict, key); return getitem(dict, key);
} catch (ExcInfo e) { } catch (ExcInfo e) {
......
...@@ -318,8 +318,8 @@ void BoxedClass::freeze() { ...@@ -318,8 +318,8 @@ void BoxedClass::freeze() {
BoxedClass::BoxedClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset, int weaklist_offset, BoxedClass::BoxedClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset, int weaklist_offset,
int instance_size, bool is_user_defined) int instance_size, bool is_user_defined)
: BoxVar(0), gc_visit(gc_visit), simple_destructor(NULL), attrs_offset(attrs_offset), is_constant(false), : BoxVar(0), attrs(HiddenClass::makeSingleton()), gc_visit(gc_visit), simple_destructor(NULL),
is_user_defined(is_user_defined), is_pyston_class(true) { attrs_offset(attrs_offset), is_constant(false), is_user_defined(is_user_defined), is_pyston_class(true) {
// Zero out the CPython tp_* slots: // Zero out the CPython tp_* slots:
memset(&tp_name, 0, (char*)(&tp_version_tag + 1) - (char*)(&tp_name)); memset(&tp_name, 0, (char*)(&tp_version_tag + 1) - (char*)(&tp_name));
...@@ -481,6 +481,43 @@ const char* getNameOfClass(BoxedClass* cls) { ...@@ -481,6 +481,43 @@ const char* getNameOfClass(BoxedClass* cls) {
return cls->tp_name; return cls->tp_name;
} }
void HiddenClass::appendAttribute(llvm::StringRef attr) {
assert(type == SINGLETON);
dependent_getattrs.invalidateAll();
assert(attr_offsets.count(attr) == 0);
int n = this->attributeArraySize();
attr_offsets[attr] = n;
}
void HiddenClass::appendAttrwrapper() {
assert(type == SINGLETON);
dependent_getattrs.invalidateAll();
assert(attrwrapper_offset == -1);
attrwrapper_offset = this->attributeArraySize();
}
void HiddenClass::delAttribute(llvm::StringRef attr) {
assert(type == SINGLETON);
dependent_getattrs.invalidateAll();
assert(attr_offsets.count(attr));
int prev_idx = attr_offsets[attr];
attr_offsets.erase(attr);
for (auto it = attr_offsets.begin(), end = attr_offsets.end(); it != end; ++it) {
assert(it->second != prev_idx);
if (it->second > prev_idx)
it->second--;
}
if (attrwrapper_offset != -1 && attrwrapper_offset > prev_idx)
attrwrapper_offset--;
}
void HiddenClass::addDependence(Rewriter* rewriter) {
assert(type == SINGLETON);
rewriter->addDependenceOn(dependent_getattrs);
}
HiddenClass* HiddenClass::getOrMakeChild(const std::string& attr) { HiddenClass* HiddenClass::getOrMakeChild(const std::string& attr) {
STAT_TIMER(t0, "us_timer_hiddenclass_getOrMakeChild"); STAT_TIMER(t0, "us_timer_hiddenclass_getOrMakeChild");
assert(type == NORMAL); assert(type == NORMAL);
...@@ -629,14 +666,16 @@ Box* Box::getattr(const std::string& attr, GetattrRewriteArgs* rewrite_args) { ...@@ -629,14 +666,16 @@ Box* Box::getattr(const std::string& attr, GetattrRewriteArgs* rewrite_args) {
return r; return r;
} }
assert(hcls->type == HiddenClass::NORMAL); assert(hcls->type == HiddenClass::NORMAL || hcls->type == HiddenClass::SINGLETON);
if (rewrite_args)
rewrite_args->out_success = true;
if (rewrite_args) { if (rewrite_args) {
if (!rewrite_args->obj_hcls_guarded) if (!rewrite_args->obj_hcls_guarded) {
rewrite_args->obj->addAttrGuard(cls->attrs_offset + HCATTRS_HCLS_OFFSET, (intptr_t)hcls); rewrite_args->obj->addAttrGuard(cls->attrs_offset + HCATTRS_HCLS_OFFSET, (intptr_t)hcls);
if (hcls->type == HiddenClass::SINGLETON)
hcls->addDependence(rewrite_args->rewriter);
}
rewrite_args->out_success = true;
} }
int offset = hcls->getOffset(attr); int offset = hcls->getOffset(attr);
...@@ -645,8 +684,6 @@ Box* Box::getattr(const std::string& attr, GetattrRewriteArgs* rewrite_args) { ...@@ -645,8 +684,6 @@ Box* Box::getattr(const std::string& attr, GetattrRewriteArgs* rewrite_args) {
} }
if (rewrite_args) { if (rewrite_args) {
// TODO using the output register as the temporary makes register allocation easier
// since we don't need to clobber a register, but does it make the code slower?
RewriterVar* r_attrs RewriterVar* r_attrs
= rewrite_args->obj->getAttr(cls->attrs_offset + HCATTRS_ATTRS_OFFSET, Location::any()); = rewrite_args->obj->getAttr(cls->attrs_offset + HCATTRS_ATTRS_OFFSET, Location::any());
rewrite_args->out_rtn = r_attrs->getAttr(offset * sizeof(Box*) + ATTRLIST_ATTRS_OFFSET, Location::any()); rewrite_args->out_rtn = r_attrs->getAttr(offset * sizeof(Box*) + ATTRLIST_ATTRS_OFFSET, Location::any());
...@@ -676,20 +713,12 @@ Box* Box::getattr(const std::string& attr, GetattrRewriteArgs* rewrite_args) { ...@@ -676,20 +713,12 @@ Box* Box::getattr(const std::string& attr, GetattrRewriteArgs* rewrite_args) {
return NULL; return NULL;
} }
void Box::addNewHCAttr(HiddenClass* new_hcls, Box* new_attr, SetattrRewriteArgs* rewrite_args) { void Box::appendNewHCAttr(Box* new_attr, SetattrRewriteArgs* rewrite_args) {
assert(cls->instancesHaveHCAttrs()); assert(cls->instancesHaveHCAttrs());
HCAttrs* attrs = getHCAttrsPtr(); HCAttrs* attrs = getHCAttrsPtr();
HiddenClass* hcls = attrs->hcls; HiddenClass* hcls = attrs->hcls;
#ifndef NDEBUG assert(hcls->type == HiddenClass::NORMAL || hcls->type == HiddenClass::SINGLETON);
// make sure we don't need to rearrange the attributes
assert(new_hcls->attributeArraySize() == hcls->attributeArraySize() + 1);
for (const auto& p : hcls->getStrAttrOffsets()) {
assert(new_hcls->getStrAttrOffsets().lookup(p.first()) == p.second);
}
if (hcls->getAttrwrapperOffset() != -1)
assert(hcls->getAttrwrapperOffset() == new_hcls->getAttrwrapperOffset());
#endif
int numattrs = hcls->attributeArraySize(); int numattrs = hcls->attributeArraySize();
...@@ -711,18 +740,11 @@ void Box::addNewHCAttr(HiddenClass* new_hcls, Box* new_attr, SetattrRewriteArgs* ...@@ -711,18 +740,11 @@ void Box::addNewHCAttr(HiddenClass* new_hcls, Box* new_attr, SetattrRewriteArgs*
r_new_array2 = rewrite_args->rewriter->call(true, (void*)gc::gc_realloc, r_oldarray, r_newsize); r_new_array2 = rewrite_args->rewriter->call(true, (void*)gc::gc_realloc, r_oldarray, r_newsize);
} }
} }
// Don't set the new hcls until after we do the allocation for the new attr_list;
// that allocation can cause a collection, and we want the collector to always
// see a consistent state between the hcls and the attr_list
attrs->hcls = new_hcls;
if (rewrite_args) { if (rewrite_args) {
r_new_array2->setAttr(numattrs * sizeof(Box*) + ATTRLIST_ATTRS_OFFSET, rewrite_args->attrval); r_new_array2->setAttr(numattrs * sizeof(Box*) + ATTRLIST_ATTRS_OFFSET, rewrite_args->attrval);
rewrite_args->obj->setAttr(cls->attrs_offset + HCATTRS_ATTRS_OFFSET, r_new_array2); rewrite_args->obj->setAttr(cls->attrs_offset + HCATTRS_ATTRS_OFFSET, r_new_array2);
RewriterVar* r_hcls = rewrite_args->rewriter->loadConst((intptr_t)new_hcls);
rewrite_args->obj->setAttr(cls->attrs_offset + HCATTRS_HCLS_OFFSET, r_hcls);
rewrite_args->out_success = true; rewrite_args->out_success = true;
} }
attrs->attr_list->attrs[numattrs] = new_attr; attrs->attr_list->attrs[numattrs] = new_attr;
...@@ -760,13 +782,14 @@ void Box::setattr(const std::string& attr, Box* val, SetattrRewriteArgs* rewrite ...@@ -760,13 +782,14 @@ void Box::setattr(const std::string& attr, Box* val, SetattrRewriteArgs* rewrite
return; return;
} }
assert(hcls->type == HiddenClass::NORMAL); assert(hcls->type == HiddenClass::NORMAL || hcls->type == HiddenClass::SINGLETON);
int offset = hcls->getOffset(attr); int offset = hcls->getOffset(attr);
if (rewrite_args) { if (rewrite_args) {
rewrite_args->obj->addAttrGuard(cls->attrs_offset + HCATTRS_HCLS_OFFSET, (intptr_t)hcls); rewrite_args->obj->addAttrGuard(cls->attrs_offset + HCATTRS_HCLS_OFFSET, (intptr_t)hcls);
// rewrite_args->rewriter->addDecision(offset == -1 ? 1 : 0); if (hcls->type == HiddenClass::SINGLETON)
hcls->addDependence(rewrite_args->rewriter);
} }
if (offset >= 0) { if (offset >= 0) {
...@@ -788,12 +811,33 @@ void Box::setattr(const std::string& attr, Box* val, SetattrRewriteArgs* rewrite ...@@ -788,12 +811,33 @@ void Box::setattr(const std::string& attr, Box* val, SetattrRewriteArgs* rewrite
} }
assert(offset == -1); assert(offset == -1);
HiddenClass* new_hcls = hcls->getOrMakeChild(attr);
// make sure we don't need to rearrange the attributes if (hcls->type == HiddenClass::NORMAL) {
assert(new_hcls->getStrAttrOffsets().lookup(attr) == hcls->attributeArraySize()); HiddenClass* new_hcls = hcls->getOrMakeChild(attr);
// make sure we don't need to rearrange the attributes
assert(new_hcls->getStrAttrOffsets().lookup(attr) == hcls->attributeArraySize());
addNewHCAttr(new_hcls, val, rewrite_args); this->appendNewHCAttr(val, rewrite_args);
attrs->hcls = new_hcls;
if (rewrite_args) {
if (!rewrite_args->out_success) {
rewrite_args = NULL;
} else {
RewriterVar* r_hcls = rewrite_args->rewriter->loadConst((intptr_t)new_hcls);
rewrite_args->obj->setAttr(cls->attrs_offset + HCATTRS_HCLS_OFFSET, r_hcls);
rewrite_args->out_success = true;
}
}
} else {
assert(hcls->type == HiddenClass::SINGLETON);
assert(!rewrite_args || !rewrite_args->out_success);
rewrite_args = NULL;
this->appendNewHCAttr(val, NULL);
hcls->appendAttribute(attr);
}
return; return;
} }
...@@ -3825,8 +3869,7 @@ void Box::delattr(const std::string& attr, DelattrRewriteArgs* rewrite_args) { ...@@ -3825,8 +3869,7 @@ void Box::delattr(const std::string& attr, DelattrRewriteArgs* rewrite_args) {
return; return;
} }
assert(hcls->type == HiddenClass::NORMAL); assert(hcls->type == HiddenClass::NORMAL || hcls->type == HiddenClass::SINGLETON);
HiddenClass* new_hcls = hcls->delAttrToMakeHC(attr);
// The order of attributes is pertained as delAttrToMakeHC constructs // The order of attributes is pertained as delAttrToMakeHC constructs
// the new HiddenClass by invoking getOrMakeChild in the prevous order // the new HiddenClass by invoking getOrMakeChild in the prevous order
...@@ -3837,7 +3880,13 @@ void Box::delattr(const std::string& attr, DelattrRewriteArgs* rewrite_args) { ...@@ -3837,7 +3880,13 @@ void Box::delattr(const std::string& attr, DelattrRewriteArgs* rewrite_args) {
Box** start = attrs->attr_list->attrs; Box** start = attrs->attr_list->attrs;
memmove(start + offset, start + offset + 1, (num_attrs - offset - 1) * sizeof(Box*)); memmove(start + offset, start + offset + 1, (num_attrs - offset - 1) * sizeof(Box*));
attrs->hcls = new_hcls; if (hcls->type == HiddenClass::NORMAL) {
HiddenClass* new_hcls = hcls->delAttrToMakeHC(attr);
attrs->hcls = new_hcls;
} else {
assert(hcls->type == HiddenClass::SINGLETON);
hcls->delAttribute(attr);
}
// guarantee the size of the attr_list equals the number of attrs // guarantee the size of the attr_list equals the number of attrs
int new_size = sizeof(HCAttrs::AttrList) + sizeof(Box*) * (num_attrs - 1); int new_size = sizeof(HCAttrs::AttrList) + sizeof(Box*) * (num_attrs - 1);
......
...@@ -383,7 +383,8 @@ static void functionDtor(Box* b) { ...@@ -383,7 +383,8 @@ static void functionDtor(Box* b) {
} }
// TODO(kmod): builtin modules are not supposed to have a __file__ attribute // TODO(kmod): builtin modules are not supposed to have a __file__ attribute
BoxedModule::BoxedModule(const std::string& name, const std::string& fn, const char* doc) { BoxedModule::BoxedModule(const std::string& name, const std::string& fn, const char* doc)
: attrs(HiddenClass::makeSingleton()) {
this->giveAttr("__name__", boxString(name)); this->giveAttr("__name__", boxString(name));
this->giveAttr("__file__", boxString(fn)); this->giveAttr("__file__", boxString(fn));
this->giveAttr("__doc__", doc ? boxStrConstant(doc) : None); this->giveAttr("__doc__", doc ? boxStrConstant(doc) : None);
...@@ -1255,7 +1256,8 @@ public: ...@@ -1255,7 +1256,8 @@ public:
// This check doesn't cover all cases, since an attrwrapper could be created around // This check doesn't cover all cases, since an attrwrapper could be created around
// a normal object which then becomes dict-backed, so we RELEASE_ASSERT later // a normal object which then becomes dict-backed, so we RELEASE_ASSERT later
// that that doesn't happen. // that that doesn't happen.
assert(b->getHCAttrsPtr()->hcls->type == HiddenClass::NORMAL); assert(b->getHCAttrsPtr()->hcls->type == HiddenClass::NORMAL
|| b->getHCAttrsPtr()->hcls->type == HiddenClass::SINGLETON);
} }
DEFAULT_CLASS(attrwrapper_cls); DEFAULT_CLASS(attrwrapper_cls);
...@@ -1374,7 +1376,7 @@ public: ...@@ -1374,7 +1376,7 @@ public:
os << "attrwrapper({"; os << "attrwrapper({";
HCAttrs* attrs = self->b->getHCAttrsPtr(); HCAttrs* attrs = self->b->getHCAttrsPtr();
RELEASE_ASSERT(attrs->hcls->type == HiddenClass::NORMAL, ""); RELEASE_ASSERT(attrs->hcls->type == HiddenClass::NORMAL || attrs->hcls->type == HiddenClass::SINGLETON, "");
bool first = true; bool first = true;
for (const auto& p : attrs->hcls->getStrAttrOffsets()) { for (const auto& p : attrs->hcls->getStrAttrOffsets()) {
if (!first) if (!first)
...@@ -1407,7 +1409,7 @@ public: ...@@ -1407,7 +1409,7 @@ public:
BoxedList* rtn = new BoxedList(); BoxedList* rtn = new BoxedList();
HCAttrs* attrs = self->b->getHCAttrsPtr(); HCAttrs* attrs = self->b->getHCAttrsPtr();
RELEASE_ASSERT(attrs->hcls->type == HiddenClass::NORMAL, ""); RELEASE_ASSERT(attrs->hcls->type == HiddenClass::NORMAL || attrs->hcls->type == HiddenClass::SINGLETON, "");
for (const auto& p : attrs->hcls->getStrAttrOffsets()) { for (const auto& p : attrs->hcls->getStrAttrOffsets()) {
listAppend(rtn, boxString(p.first())); listAppend(rtn, boxString(p.first()));
} }
...@@ -1422,7 +1424,7 @@ public: ...@@ -1422,7 +1424,7 @@ public:
BoxedList* rtn = new BoxedList(); BoxedList* rtn = new BoxedList();
HCAttrs* attrs = self->b->getHCAttrsPtr(); HCAttrs* attrs = self->b->getHCAttrsPtr();
RELEASE_ASSERT(attrs->hcls->type == HiddenClass::NORMAL, ""); RELEASE_ASSERT(attrs->hcls->type == HiddenClass::NORMAL || attrs->hcls->type == HiddenClass::SINGLETON, "");
for (const auto& p : attrs->hcls->getStrAttrOffsets()) { for (const auto& p : attrs->hcls->getStrAttrOffsets()) {
listAppend(rtn, attrs->attr_list->attrs[p.second]); listAppend(rtn, attrs->attr_list->attrs[p.second]);
} }
...@@ -1437,7 +1439,7 @@ public: ...@@ -1437,7 +1439,7 @@ public:
BoxedList* rtn = new BoxedList(); BoxedList* rtn = new BoxedList();
HCAttrs* attrs = self->b->getHCAttrsPtr(); HCAttrs* attrs = self->b->getHCAttrsPtr();
RELEASE_ASSERT(attrs->hcls->type == HiddenClass::NORMAL, ""); RELEASE_ASSERT(attrs->hcls->type == HiddenClass::NORMAL || attrs->hcls->type == HiddenClass::SINGLETON, "");
for (const auto& p : attrs->hcls->getStrAttrOffsets()) { for (const auto& p : attrs->hcls->getStrAttrOffsets()) {
BoxedTuple* t = BoxedTuple::create({ boxString(p.first()), attrs->attr_list->attrs[p.second] }); BoxedTuple* t = BoxedTuple::create({ boxString(p.first()), attrs->attr_list->attrs[p.second] });
listAppend(rtn, t); listAppend(rtn, t);
...@@ -1452,7 +1454,7 @@ public: ...@@ -1452,7 +1454,7 @@ public:
BoxedDict* rtn = new BoxedDict(); BoxedDict* rtn = new BoxedDict();
HCAttrs* attrs = self->b->getHCAttrsPtr(); HCAttrs* attrs = self->b->getHCAttrsPtr();
RELEASE_ASSERT(attrs->hcls->type == HiddenClass::NORMAL, ""); RELEASE_ASSERT(attrs->hcls->type == HiddenClass::NORMAL || attrs->hcls->type == HiddenClass::SINGLETON, "");
for (const auto& p : attrs->hcls->getStrAttrOffsets()) { for (const auto& p : attrs->hcls->getStrAttrOffsets()) {
rtn->d[boxString(p.first())] = attrs->attr_list->attrs[p.second]; rtn->d[boxString(p.first())] = attrs->attr_list->attrs[p.second];
} }
...@@ -1464,7 +1466,7 @@ public: ...@@ -1464,7 +1466,7 @@ public:
AttrWrapper* self = static_cast<AttrWrapper*>(_self); AttrWrapper* self = static_cast<AttrWrapper*>(_self);
HCAttrs* attrs = self->b->getHCAttrsPtr(); HCAttrs* attrs = self->b->getHCAttrsPtr();
RELEASE_ASSERT(attrs->hcls->type == HiddenClass::NORMAL, ""); RELEASE_ASSERT(attrs->hcls->type == HiddenClass::NORMAL || attrs->hcls->type == HiddenClass::SINGLETON, "");
return boxInt(attrs->hcls->getStrAttrOffsets().size()); return boxInt(attrs->hcls->getStrAttrOffsets().size());
} }
...@@ -1477,7 +1479,7 @@ public: ...@@ -1477,7 +1479,7 @@ public:
AttrWrapper* container = static_cast<AttrWrapper*>(_container); AttrWrapper* container = static_cast<AttrWrapper*>(_container);
HCAttrs* attrs = container->b->getHCAttrsPtr(); HCAttrs* attrs = container->b->getHCAttrsPtr();
RELEASE_ASSERT(attrs->hcls->type == HiddenClass::NORMAL, ""); RELEASE_ASSERT(attrs->hcls->type == HiddenClass::NORMAL || attrs->hcls->type == HiddenClass::SINGLETON, "");
for (const auto& p : attrs->hcls->getStrAttrOffsets()) { for (const auto& p : attrs->hcls->getStrAttrOffsets()) {
self->b->setattr(p.first(), attrs->attr_list->attrs[p.second], NULL); self->b->setattr(p.first(), attrs->attr_list->attrs[p.second], NULL);
} }
...@@ -1506,14 +1508,14 @@ public: ...@@ -1506,14 +1508,14 @@ public:
AttrWrapperIter::AttrWrapperIter(AttrWrapper* aw) { AttrWrapperIter::AttrWrapperIter(AttrWrapper* aw) {
hcls = aw->b->getHCAttrsPtr()->hcls; hcls = aw->b->getHCAttrsPtr()->hcls;
assert(hcls); assert(hcls);
RELEASE_ASSERT(hcls->type == HiddenClass::NORMAL, ""); RELEASE_ASSERT(hcls->type == HiddenClass::NORMAL || hcls->type == HiddenClass::SINGLETON, "");
it = hcls->getStrAttrOffsets().begin(); it = hcls->getStrAttrOffsets().begin();
} }
Box* AttrWrapperIter::hasnext(Box* _self) { Box* AttrWrapperIter::hasnext(Box* _self) {
RELEASE_ASSERT(_self->cls == attrwrapperiter_cls, ""); RELEASE_ASSERT(_self->cls == attrwrapperiter_cls, "");
AttrWrapperIter* self = static_cast<AttrWrapperIter*>(_self); AttrWrapperIter* self = static_cast<AttrWrapperIter*>(_self);
RELEASE_ASSERT(self->hcls->type == HiddenClass::NORMAL, ""); RELEASE_ASSERT(self->hcls->type == HiddenClass::NORMAL || self->hcls->type == HiddenClass::SINGLETON, "");
return boxBool(self->it != self->hcls->getStrAttrOffsets().end()); return boxBool(self->it != self->hcls->getStrAttrOffsets().end());
} }
...@@ -1521,7 +1523,7 @@ Box* AttrWrapperIter::hasnext(Box* _self) { ...@@ -1521,7 +1523,7 @@ Box* AttrWrapperIter::hasnext(Box* _self) {
Box* AttrWrapperIter::next(Box* _self) { Box* AttrWrapperIter::next(Box* _self) {
RELEASE_ASSERT(_self->cls == attrwrapperiter_cls, ""); RELEASE_ASSERT(_self->cls == attrwrapperiter_cls, "");
AttrWrapperIter* self = static_cast<AttrWrapperIter*>(_self); AttrWrapperIter* self = static_cast<AttrWrapperIter*>(_self);
RELEASE_ASSERT(self->hcls->type == HiddenClass::NORMAL, ""); RELEASE_ASSERT(self->hcls->type == HiddenClass::NORMAL || self->hcls->type == HiddenClass::SINGLETON, "");
assert(self->it != self->hcls->getStrAttrOffsets().end()); assert(self->it != self->hcls->getStrAttrOffsets().end());
Box* r = boxString(self->it->first()); Box* r = boxString(self->it->first());
...@@ -1541,8 +1543,17 @@ Box* Box::getAttrWrapper() { ...@@ -1541,8 +1543,17 @@ Box* Box::getAttrWrapper() {
int offset = hcls->getAttrwrapperOffset(); int offset = hcls->getAttrwrapperOffset();
if (offset == -1) { if (offset == -1) {
Box* aw = new AttrWrapper(this); Box* aw = new AttrWrapper(this);
addNewHCAttr(hcls->getAttrwrapperChild(), aw, NULL); if (hcls->type == HiddenClass::NORMAL) {
return aw; auto new_hcls = hcls->getAttrwrapperChild();
appendNewHCAttr(aw, NULL);
attrs->hcls = new_hcls;
return aw;
} else {
assert(hcls->type == HiddenClass::SINGLETON);
appendNewHCAttr(aw, NULL);
hcls->appendAttrwrapper();
return aw;
}
} }
return attrs->attr_list->attrs[offset]; return attrs->attr_list->attrs[offset];
} }
......
...@@ -278,6 +278,7 @@ public: ...@@ -278,6 +278,7 @@ public:
enum HCType { enum HCType {
NORMAL, // attributes stored in attributes array, name->offset map stored in hidden class NORMAL, // attributes stored in attributes array, name->offset map stored in hidden class
DICT_BACKED, // first attribute in array is a dict-like object which stores the attributes DICT_BACKED, // first attribute in array is a dict-like object which stores the attributes
SINGLETON, // name->offset map stored in hidden class, but hcls is mutable
} const type; } const type;
static HiddenClass* dict_backed; static HiddenClass* dict_backed;
...@@ -291,14 +292,21 @@ private: ...@@ -291,14 +292,21 @@ private:
} }
} }
// These fields only make sense for NORMAL hidden classes: // These fields only make sense for NORMAL or SINGLETON hidden classes:
llvm::StringMap<int> attr_offsets; llvm::StringMap<int> attr_offsets;
ContiguousMap<llvm::StringRef, HiddenClass*, llvm::StringMap<int>> children;
// If >= 0, is the offset where we stored an attrwrapper object // If >= 0, is the offset where we stored an attrwrapper object
int attrwrapper_offset = -1; int attrwrapper_offset = -1;
// These are only for NORMAL hidden classes:
ContiguousMap<llvm::StringRef, HiddenClass*, llvm::StringMap<int>> children;
HiddenClass* attrwrapper_child = NULL; HiddenClass* attrwrapper_child = NULL;
// Only for SINGLETON hidden classes:
ICInvalidator dependent_getattrs;
public: public:
static HiddenClass* makeSingleton() { return new HiddenClass(SINGLETON); }
static HiddenClass* makeRoot() { static HiddenClass* makeRoot() {
#ifndef NDEBUG #ifndef NDEBUG
static bool made = false; static bool made = false;
...@@ -329,7 +337,7 @@ public: ...@@ -329,7 +337,7 @@ public:
if (type == DICT_BACKED) if (type == DICT_BACKED)
return 1; return 1;
ASSERT(type == NORMAL, "%d", type); ASSERT(type == NORMAL || type == SINGLETON, "%d", type);
int r = attr_offsets.size(); int r = attr_offsets.size();
if (attrwrapper_offset != -1) if (attrwrapper_offset != -1)
r += 1; r += 1;
...@@ -338,18 +346,18 @@ public: ...@@ -338,18 +346,18 @@ public:
// The mapping from string attribute names to attribute offsets. There may be other objects in the attributes // The mapping from string attribute names to attribute offsets. There may be other objects in the attributes
// array. // array.
// Only valid for NORMAL hidden classes // Only valid for NORMAL or SINGLETON hidden classes
const llvm::StringMap<int>& getStrAttrOffsets() { const llvm::StringMap<int>& getStrAttrOffsets() {
assert(type == NORMAL); assert(type == NORMAL || type == SINGLETON);
return attr_offsets; return attr_offsets;
} }
// Only valid for NORMAL hidden classes: // Only valid for NORMAL hidden classes:
HiddenClass* getOrMakeChild(const std::string& attr); HiddenClass* getOrMakeChild(const std::string& attr);
// Only valid for NORMAL hidden classes: // Only valid for NORMAL or SINGLETON hidden classes:
int getOffset(const std::string& attr) { int getOffset(const std::string& attr) {
assert(type == NORMAL); assert(type == NORMAL || type == SINGLETON);
auto it = attr_offsets.find(attr); auto it = attr_offsets.find(attr);
if (it == attr_offsets.end()) if (it == attr_offsets.end())
return -1; return -1;
...@@ -357,10 +365,17 @@ public: ...@@ -357,10 +365,17 @@ public:
} }
int getAttrwrapperOffset() { int getAttrwrapperOffset() {
assert(type == NORMAL); assert(type == NORMAL || type == SINGLETON);
return attrwrapper_offset; return attrwrapper_offset;
} }
// Only valid for SINGLETON hidden classes:
void appendAttribute(llvm::StringRef attr);
void appendAttrwrapper();
void delAttribute(llvm::StringRef attr);
void addDependence(Rewriter* rewriter);
// Only valid for NORMAL hidden classes:
HiddenClass* getAttrwrapperChild(); HiddenClass* getAttrwrapperChild();
// Only valid for NORMAL hidden classes: // Only valid for NORMAL hidden classes:
......
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