Commit 2358b49b authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge branch 'tp_dictoffset'

parents 338af286 5b2747b1
...@@ -869,6 +869,10 @@ runpy_%: %.py ext_python ...@@ -869,6 +869,10 @@ runpy_%: %.py ext_python
PYTHONPATH=test/test_extension/build/lib.linux-x86_64-2.7 python $< PYTHONPATH=test/test_extension/build/lib.linux-x86_64-2.7 python $<
$(call make_search,runpy_%) $(call make_search,runpy_%)
check_%: %.py ext_python ext_pyston
$(MAKE) check_dbg ARGS="$(patsubst %.py,%,$(notdir $<)) -K"
$(call make_search,check_%)
dbgpy_%: %.py ext_pythondbg dbgpy_%: %.py ext_pythondbg
export PYTHON_VERSION=$$(python2.7-dbg -V 2>&1 | awk '{print $$2}'); PYTHONPATH=test/test_extension/build/lib.linux-x86_64-2.7-pydebug $(GDB) --ex "dir $(DEPS_DIR)/python-src/python2.7-$$PYTHON_VERSION/debian" $(GDB_CMDS) --args python2.7-dbg $< export PYTHON_VERSION=$$(python2.7-dbg -V 2>&1 | awk '{print $$2}'); PYTHONPATH=test/test_extension/build/lib.linux-x86_64-2.7-pydebug $(GDB) --ex "dir $(DEPS_DIR)/python-src/python2.7-$$PYTHON_VERSION/debian" $(GDB_CMDS) --args python2.7-dbg $<
$(call make_search,dbgpy_%) $(call make_search,dbgpy_%)
......
...@@ -1762,9 +1762,6 @@ extern "C" int PyType_Ready(PyTypeObject* cls) noexcept { ...@@ -1762,9 +1762,6 @@ extern "C" int PyType_Ready(PyTypeObject* cls) noexcept {
cls->gc_visit = &conservativeGCHandler; cls->gc_visit = &conservativeGCHandler;
cls->is_user_defined = true; cls->is_user_defined = true;
// TODO not sure how we can handle extension types that manually
// specify a dict...
RELEASE_ASSERT(cls->tp_dictoffset == 0, "");
// this should get automatically initialized to 0 on this path: // this should get automatically initialized to 0 on this path:
assert(cls->attrs_offset == 0); assert(cls->attrs_offset == 0);
......
...@@ -1274,8 +1274,13 @@ public: ...@@ -1274,8 +1274,13 @@ public:
return c == cls; return c == cls;
} }
bool canStaticallyResolveGetattrs() {
return (cls->is_constant && !cls->instancesHaveHCAttrs() && !cls->instancesHaveDictAttrs()
&& cls->hasGenericGetattr());
}
CompilerType* getattrType(const std::string* attr, bool cls_only) override { CompilerType* getattrType(const std::string* attr, bool cls_only) override {
if (cls->is_constant && !cls->instancesHaveAttrs() && cls->hasGenericGetattr()) { if (canStaticallyResolveGetattrs()) {
Box* rtattr = cls->getattr(*attr); Box* rtattr = cls->getattr(*attr);
if (rtattr == NULL) if (rtattr == NULL)
return UNDEF; return UNDEF;
...@@ -1300,7 +1305,7 @@ public: ...@@ -1300,7 +1305,7 @@ public:
CompilerVariable* getattr(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var, CompilerVariable* getattr(IREmitter& emitter, const OpInfo& info, ConcreteCompilerVariable* var,
const std::string* attr, bool cls_only) override { const std::string* attr, bool cls_only) override {
// printf("%s.getattr %s\n", debugName().c_str(), attr->c_str()); // printf("%s.getattr %s\n", debugName().c_str(), attr->c_str());
if (cls->is_constant && !cls->instancesHaveAttrs() && cls->hasGenericGetattr()) { if (canStaticallyResolveGetattrs()) {
Box* rtattr = cls->getattr(*attr); Box* rtattr = cls->getattr(*attr);
if (rtattr == NULL) { if (rtattr == NULL) {
llvm::CallSite call = emitter.createCall2(info.unw_info, g.funcs.raiseAttributeErrorStr, llvm::CallSite call = emitter.createCall2(info.unw_info, g.funcs.raiseAttributeErrorStr,
...@@ -1346,7 +1351,7 @@ public: ...@@ -1346,7 +1351,7 @@ public:
const std::vector<CompilerVariable*>& args, const std::vector<CompilerVariable*>& args,
const std::vector<const std::string*>* keyword_names, const std::vector<const std::string*>* keyword_names,
bool raise_on_missing = true) { bool raise_on_missing = true) {
if (!cls->is_constant || cls->instancesHaveAttrs() || !cls->hasGenericGetattr()) if (!canStaticallyResolveGetattrs())
return NULL; return NULL;
Box* rtattr = cls->getattr(*attr); Box* rtattr = cls->getattr(*attr);
......
...@@ -381,6 +381,7 @@ public: ...@@ -381,6 +381,7 @@ public:
HCAttrs() : hcls(root_hcls), attr_list(nullptr) {} HCAttrs() : hcls(root_hcls), attr_list(nullptr) {}
}; };
class BoxedDict;
class BoxedString; class BoxedString;
class Box { class Box {
...@@ -396,7 +397,8 @@ public: ...@@ -396,7 +397,8 @@ public:
llvm::iterator_range<BoxIterator> pyElements(); llvm::iterator_range<BoxIterator> pyElements();
HCAttrs* getAttrsPtr(); HCAttrs* getHCAttrsPtr();
BoxedDict* getDict();
void setattr(const std::string& attr, Box* val, SetattrRewriteArgs* rewrite_args); void setattr(const std::string& attr, Box* val, SetattrRewriteArgs* rewrite_args);
void giveAttr(const std::string& attr, Box* val) { void giveAttr(const std::string& attr, Box* val) {
......
...@@ -91,12 +91,15 @@ extern "C" Box* dir(Box* obj) { ...@@ -91,12 +91,15 @@ extern "C" Box* dir(Box* obj) {
for (auto const& kv : obj->cls->attrs.hcls->attr_offsets) { for (auto const& kv : obj->cls->attrs.hcls->attr_offsets) {
listAppend(result, boxString(kv.first)); listAppend(result, boxString(kv.first));
} }
if (obj->cls->instancesHaveAttrs()) { if (obj->cls->instancesHaveHCAttrs()) {
HCAttrs* attrs = obj->getAttrsPtr(); HCAttrs* attrs = obj->getHCAttrsPtr();
for (auto const& kv : attrs->hcls->attr_offsets) { for (auto const& kv : attrs->hcls->attr_offsets) {
listAppend(result, boxString(kv.first)); listAppend(result, boxString(kv.first));
} }
} }
if (obj->cls->instancesHaveDictAttrs()) {
Py_FatalError("unimplemented");
}
return result; return result;
} }
......
...@@ -64,6 +64,13 @@ static const std::string _call_str("__call__"), _new_str("__new__"), _init_str(" ...@@ -64,6 +64,13 @@ static const std::string _call_str("__call__"), _new_str("__new__"), _init_str("
static const std::string _getattr_str("__getattr__"); static const std::string _getattr_str("__getattr__");
static const std::string _getattribute_str("__getattribute__"); static const std::string _getattribute_str("__getattribute__");
#if 0
void REWRITE_ABORTED(const char* reason) {
}
#else
#define REWRITE_ABORTED(reason) ((void)(reason))
#endif
struct GetattrRewriteArgs { struct GetattrRewriteArgs {
Rewriter* rewriter; Rewriter* rewriter;
RewriterVar* obj; RewriterVar* obj;
...@@ -494,15 +501,34 @@ HiddenClass* HiddenClass::delAttrToMakeHC(const std::string& attr) { ...@@ -494,15 +501,34 @@ HiddenClass* HiddenClass::delAttrToMakeHC(const std::string& attr) {
return cur; return cur;
} }
HCAttrs* Box::getAttrsPtr() { HCAttrs* Box::getHCAttrsPtr() {
assert(cls->instancesHaveAttrs()); assert(cls->instancesHaveHCAttrs());
char* p = reinterpret_cast<char*>(this); char* p = reinterpret_cast<char*>(this);
p += cls->attrs_offset; p += cls->attrs_offset;
return reinterpret_cast<HCAttrs*>(p); return reinterpret_cast<HCAttrs*>(p);
} }
BoxedDict* Box::getDict() {
assert(cls->instancesHaveDictAttrs());
char* p = reinterpret_cast<char*>(this);
p += cls->tp_dictoffset;
BoxedDict** d_ptr = reinterpret_cast<BoxedDict**>(p);
BoxedDict* d = *d_ptr;
if (!d) {
d = *d_ptr = new BoxedDict();
}
assert(d->cls == dict_cls);
return d;
}
Box* Box::getattr(const std::string& attr, GetattrRewriteArgs* rewrite_args) { Box* Box::getattr(const std::string& attr, GetattrRewriteArgs* rewrite_args) {
if (rewrite_args)
rewrite_args->obj->addAttrGuard(BOX_CLS_OFFSET, (intptr_t)cls);
// Have to guard on the memory layout of this object. // Have to guard on the memory layout of this object.
// Right now, guard on the specific Python-class, which in turn // Right now, guard on the specific Python-class, which in turn
// specifies the C structure. // specifies the C structure.
...@@ -512,41 +538,55 @@ Box* Box::getattr(const std::string& attr, GetattrRewriteArgs* rewrite_args) { ...@@ -512,41 +538,55 @@ Box* Box::getattr(const std::string& attr, GetattrRewriteArgs* rewrite_args) {
// Only matters if we end up getting multiple classes with the same // Only matters if we end up getting multiple classes with the same
// structure (ex user class) and the same hidden classes, because // structure (ex user class) and the same hidden classes, because
// otherwise the guard will fail anyway.; // otherwise the guard will fail anyway.;
if (rewrite_args) { if (cls->instancesHaveHCAttrs()) {
rewrite_args->obj->addAttrGuard(BOX_CLS_OFFSET, (intptr_t)cls); if (rewrite_args)
rewrite_args->out_success = true; rewrite_args->out_success = true;
}
if (!cls->instancesHaveAttrs()) { HCAttrs* attrs = getHCAttrsPtr();
return NULL; HiddenClass* hcls = attrs->hcls;
}
HCAttrs* attrs = getAttrsPtr(); if (rewrite_args) {
HiddenClass* hcls = attrs->hcls; if (!rewrite_args->obj_hcls_guarded)
rewrite_args->obj->addAttrGuard(cls->attrs_offset + HCATTRS_HCLS_OFFSET, (intptr_t)hcls);
}
if (rewrite_args) { int offset = hcls->getOffset(attr);
if (!rewrite_args->obj_hcls_guarded) if (offset == -1) {
rewrite_args->obj->addAttrGuard(cls->attrs_offset + HCATTRS_HCLS_OFFSET, (intptr_t)hcls); return NULL;
} }
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
= 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());
}
int offset = hcls->getOffset(attr); Box* rtn = attrs->attr_list->attrs[offset];
if (offset == -1) { return rtn;
return NULL;
} }
if (rewrite_args) { if (cls->instancesHaveDictAttrs()) {
// TODO using the output register as the temporary makes register allocation easier if (rewrite_args)
// since we don't need to clobber a register, but does it make the code slower? REWRITE_ABORTED("");
RewriterVar* r_attrs = 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()); BoxedDict* d = getDict();
Box* key = boxString(attr);
auto it = d->d.find(key);
if (it == d->d.end())
return NULL;
return it->second;
} }
Box* rtn = attrs->attr_list->attrs[offset]; if (rewrite_args)
return rtn; rewrite_args->out_success = true;
return NULL;
} }
void Box::setattr(const std::string& attr, Box* val, SetattrRewriteArgs* rewrite_args) { void Box::setattr(const std::string& attr, Box* val, SetattrRewriteArgs* rewrite_args) {
assert(cls->instancesHaveAttrs());
assert(gc::isValidGCObject(val)); assert(gc::isValidGCObject(val));
// Have to guard on the memory layout of this object. // Have to guard on the memory layout of this object.
...@@ -561,84 +601,96 @@ void Box::setattr(const std::string& attr, Box* val, SetattrRewriteArgs* rewrite ...@@ -561,84 +601,96 @@ void Box::setattr(const std::string& attr, Box* val, SetattrRewriteArgs* rewrite
if (rewrite_args) if (rewrite_args)
rewrite_args->obj->addAttrGuard(BOX_CLS_OFFSET, (intptr_t)cls); rewrite_args->obj->addAttrGuard(BOX_CLS_OFFSET, (intptr_t)cls);
static const std::string none_str("None"); static const std::string none_str("None");
RELEASE_ASSERT(attr != none_str || this == builtins_module, "can't assign to None"); RELEASE_ASSERT(attr != none_str || this == builtins_module, "can't assign to None");
HCAttrs* attrs = getAttrsPtr(); if (cls->instancesHaveHCAttrs()) {
HiddenClass* hcls = attrs->hcls; HCAttrs* attrs = getHCAttrsPtr();
int numattrs = hcls->attr_offsets.size(); HiddenClass* hcls = attrs->hcls;
int numattrs = hcls->attr_offsets.size();
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); // rewrite_args->rewriter->addDecision(offset == -1 ? 1 : 0);
} }
if (offset >= 0) { if (offset >= 0) {
assert(offset < numattrs); assert(offset < numattrs);
Box* prev = attrs->attr_list->attrs[offset]; Box* prev = attrs->attr_list->attrs[offset];
attrs->attr_list->attrs[offset] = val; attrs->attr_list->attrs[offset] = val;
if (rewrite_args) { if (rewrite_args) {
RewriterVar* r_hattrs RewriterVar* r_hattrs
= rewrite_args->obj->getAttr(cls->attrs_offset + HCATTRS_ATTRS_OFFSET, Location::any()); = rewrite_args->obj->getAttr(cls->attrs_offset + HCATTRS_ATTRS_OFFSET, Location::any());
r_hattrs->setAttr(offset * sizeof(Box*) + ATTRLIST_ATTRS_OFFSET, rewrite_args->attrval); r_hattrs->setAttr(offset * sizeof(Box*) + ATTRLIST_ATTRS_OFFSET, rewrite_args->attrval);
rewrite_args->out_success = true; rewrite_args->out_success = true;
} }
return; return;
} }
assert(offset == -1); assert(offset == -1);
HiddenClass* new_hcls = hcls->getOrMakeChild(attr); HiddenClass* new_hcls = hcls->getOrMakeChild(attr);
// TODO need to make sure we don't need to rearrange the attributes // TODO need to make sure we don't need to rearrange the attributes
assert(new_hcls->attr_offsets[attr] == numattrs); assert(new_hcls->attr_offsets[attr] == numattrs);
#ifndef NDEBUG #ifndef NDEBUG
for (const auto& p : hcls->attr_offsets) { for (const auto& p : hcls->attr_offsets) {
assert(new_hcls->attr_offsets[p.first] == p.second); assert(new_hcls->attr_offsets[p.first] == p.second);
} }
#endif #endif
RewriterVar* r_new_array2 = NULL; RewriterVar* r_new_array2 = NULL;
int new_size = sizeof(HCAttrs::AttrList) + sizeof(Box*) * (numattrs + 1); int new_size = sizeof(HCAttrs::AttrList) + sizeof(Box*) * (numattrs + 1);
if (numattrs == 0) { if (numattrs == 0) {
attrs->attr_list = (HCAttrs::AttrList*)gc_alloc(new_size, gc::GCKind::UNTRACKED); attrs->attr_list = (HCAttrs::AttrList*)gc_alloc(new_size, gc::GCKind::UNTRACKED);
if (rewrite_args) { if (rewrite_args) {
RewriterVar* r_newsize = rewrite_args->rewriter->loadConst(new_size, Location::forArg(0)); RewriterVar* r_newsize = rewrite_args->rewriter->loadConst(new_size, Location::forArg(0));
RewriterVar* r_kind = rewrite_args->rewriter->loadConst((int)gc::GCKind::UNTRACKED, Location::forArg(1)); RewriterVar* r_kind
r_new_array2 = rewrite_args->rewriter->call(false, (void*)gc::gc_alloc, r_newsize, r_kind); = rewrite_args->rewriter->loadConst((int)gc::GCKind::UNTRACKED, Location::forArg(1));
r_new_array2 = rewrite_args->rewriter->call(false, (void*)gc::gc_alloc, r_newsize, r_kind);
}
} else {
attrs->attr_list = (HCAttrs::AttrList*)gc::gc_realloc(attrs->attr_list, new_size);
if (rewrite_args) {
RewriterVar* r_oldarray
= rewrite_args->obj->getAttr(cls->attrs_offset + HCATTRS_ATTRS_OFFSET, Location::forArg(0));
RewriterVar* r_newsize = rewrite_args->rewriter->loadConst(new_size, Location::forArg(1));
r_new_array2 = rewrite_args->rewriter->call(false, (void*)gc::gc_realloc, r_oldarray, r_newsize);
}
} }
} else { // Don't set the new hcls until after we do the allocation for the new attr_list;
attrs->attr_list = (HCAttrs::AttrList*)gc::gc_realloc(attrs->attr_list, new_size); // 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) {
RewriterVar* r_oldarray r_new_array2->setAttr(numattrs * sizeof(Box*) + ATTRLIST_ATTRS_OFFSET, rewrite_args->attrval);
= rewrite_args->obj->getAttr(cls->attrs_offset + HCATTRS_ATTRS_OFFSET, Location::forArg(0)); rewrite_args->obj->setAttr(cls->attrs_offset + HCATTRS_ATTRS_OFFSET, r_new_array2);
RewriterVar* r_newsize = rewrite_args->rewriter->loadConst(new_size, Location::forArg(1));
r_new_array2 = rewrite_args->rewriter->call(false, (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) { RewriterVar* r_hcls = rewrite_args->rewriter->loadConst((intptr_t)new_hcls);
r_new_array2->setAttr(numattrs * sizeof(Box*) + ATTRLIST_ATTRS_OFFSET, rewrite_args->attrval); rewrite_args->obj->setAttr(cls->attrs_offset + HCATTRS_HCLS_OFFSET, r_hcls);
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->out_success = true;
rewrite_args->obj->setAttr(cls->attrs_offset + HCATTRS_HCLS_OFFSET, r_hcls); }
attrs->attr_list->attrs[numattrs] = val;
return;
}
rewrite_args->out_success = true; if (cls->instancesHaveDictAttrs()) {
BoxedDict* d = getDict();
d->d[boxString(attr)] = val;
return;
} }
attrs->attr_list->attrs[numattrs] = val;
// Unreachable
abort();
} }
Box* typeLookup(BoxedClass* cls, const std::string& attr, GetattrRewriteArgs* rewrite_args) { Box* typeLookup(BoxedClass* cls, const std::string& attr, GetattrRewriteArgs* rewrite_args) {
...@@ -951,6 +1003,7 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, const ...@@ -951,6 +1003,7 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, const
} }
rewrite_args = NULL; rewrite_args = NULL;
REWRITE_ABORTED("");
char* rtn = reinterpret_cast<char*>((char*)obj + member_desc->offset); char* rtn = reinterpret_cast<char*>((char*)obj + member_desc->offset);
return boxString(std::string(rtn)); return boxString(std::string(rtn));
} }
...@@ -962,6 +1015,7 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, const ...@@ -962,6 +1015,7 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, const
else if (descr->cls == property_cls) { else if (descr->cls == property_cls) {
rewrite_args = NULL; // TODO rewrite_args = NULL; // TODO
REWRITE_ABORTED("");
BoxedProperty* prop = static_cast<BoxedProperty*>(descr); BoxedProperty* prop = static_cast<BoxedProperty*>(descr);
if (prop->prop_get == NULL || prop->prop_get == None) { if (prop->prop_get == NULL || prop->prop_get == None) {
...@@ -1184,8 +1238,10 @@ Box* getattrInternalGeneral(Box* obj, const std::string& attr, GetattrRewriteArg ...@@ -1184,8 +1238,10 @@ Box* getattrInternalGeneral(Box* obj, const std::string& attr, GetattrRewriteArg
if (_set_) { if (_set_) {
// Have to abort because we're about to call now, but there will be before more // Have to abort because we're about to call now, but there will be before more
// guards between this call and the next... // guards between this call and the next...
if (for_call) if (for_call) {
rewrite_args = NULL; rewrite_args = NULL;
REWRITE_ABORTED("");
}
Box* res; Box* res;
if (rewrite_args) { if (rewrite_args) {
...@@ -1285,8 +1341,10 @@ Box* getattrInternalGeneral(Box* obj, const std::string& attr, GetattrRewriteArg ...@@ -1285,8 +1341,10 @@ Box* getattrInternalGeneral(Box* obj, const std::string& attr, GetattrRewriteArg
if (local_get) { if (local_get) {
Box* res; Box* res;
if (for_call) if (for_call) {
rewrite_args = NULL; rewrite_args = NULL;
REWRITE_ABORTED("");
}
if (rewrite_args) { if (rewrite_args) {
CallRewriteArgs crewrite_args(rewrite_args->rewriter, r_get, rewrite_args->destination); CallRewriteArgs crewrite_args(rewrite_args->rewriter, r_get, rewrite_args->destination);
...@@ -1330,8 +1388,10 @@ Box* getattrInternalGeneral(Box* obj, const std::string& attr, GetattrRewriteArg ...@@ -1330,8 +1388,10 @@ Box* getattrInternalGeneral(Box* obj, const std::string& attr, GetattrRewriteArg
// the result. // the result.
if (_get_) { if (_get_) {
// this could happen for the callattr path... // this could happen for the callattr path...
if (for_call) if (for_call) {
rewrite_args = NULL; rewrite_args = NULL;
REWRITE_ABORTED("");
}
Box* res; Box* res;
if (rewrite_args) { if (rewrite_args) {
...@@ -1366,6 +1426,7 @@ Box* getattrInternalGeneral(Box* obj, const std::string& attr, GetattrRewriteArg ...@@ -1366,6 +1426,7 @@ Box* getattrInternalGeneral(Box* obj, const std::string& attr, GetattrRewriteArg
// Don't need to pass icentry args, since we special-case __getattribute__ and __getattr__ to use // Don't need to pass icentry args, since we special-case __getattribute__ and __getattr__ to use
// invalidation rather than guards // invalidation rather than guards
rewrite_args = NULL; rewrite_args = NULL;
REWRITE_ABORTED("");
Box* getattr = typeLookup(obj->cls, "__getattr__", NULL); Box* getattr = typeLookup(obj->cls, "__getattr__", NULL);
if (getattr) { if (getattr) {
Box* boxstr = boxString(attr); Box* boxstr = boxString(attr);
...@@ -1403,7 +1464,8 @@ extern "C" Box* getattr(Box* obj, const char* attr) { ...@@ -1403,7 +1464,8 @@ extern "C" Box* getattr(Box* obj, const char* attr) {
} }
if (strcmp(attr, "__dict__") == 0) { if (strcmp(attr, "__dict__") == 0) {
if (obj->cls->instancesHaveAttrs()) // TODO this is wrong, should be added at the class level as a getset
if (obj->cls->instancesHaveHCAttrs())
return makeAttrWrapper(obj); return makeAttrWrapper(obj);
} }
...@@ -1509,6 +1571,8 @@ void setattrInternal(Box* obj, const std::string& attr, Box* val, SetattrRewrite ...@@ -1509,6 +1571,8 @@ void setattrInternal(Box* obj, const std::string& attr, Box* val, SetattrRewrite
BoxedClass* self = static_cast<BoxedClass*>(obj); BoxedClass* self = static_cast<BoxedClass*>(obj);
if (attr == _getattr_str || attr == _getattribute_str) { if (attr == _getattr_str || attr == _getattribute_str) {
if (rewrite_args)
REWRITE_ABORTED("");
// Will have to embed the clear in the IC, so just disable the patching for now: // Will have to embed the clear in the IC, so just disable the patching for now:
rewrite_args = NULL; rewrite_args = NULL;
...@@ -1521,8 +1585,10 @@ void setattrInternal(Box* obj, const std::string& attr, Box* val, SetattrRewrite ...@@ -1521,8 +1585,10 @@ void setattrInternal(Box* obj, const std::string& attr, Box* val, SetattrRewrite
raiseExcHelper(TypeError, "readonly attribute"); raiseExcHelper(TypeError, "readonly attribute");
bool touched_slot = update_slot(self, attr); bool touched_slot = update_slot(self, attr);
if (touched_slot) if (touched_slot) {
rewrite_args = NULL; rewrite_args = NULL;
REWRITE_ABORTED("");
}
} }
} }
...@@ -1532,7 +1598,7 @@ extern "C" void setattr(Box* obj, const char* attr, Box* attr_val) { ...@@ -1532,7 +1598,7 @@ extern "C" void setattr(Box* obj, const char* attr, Box* attr_val) {
static StatCounter slowpath_setattr("slowpath_setattr"); static StatCounter slowpath_setattr("slowpath_setattr");
slowpath_setattr.log(); slowpath_setattr.log();
if (!obj->cls->instancesHaveAttrs()) { if (!obj->cls->instancesHaveHCAttrs() && !obj->cls->instancesHaveDictAttrs()) {
raiseAttributeError(obj, attr); raiseAttributeError(obj, attr);
} }
...@@ -2013,6 +2079,7 @@ extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope ...@@ -2013,6 +2079,7 @@ extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope
Box* rtn; Box* rtn;
if (val->cls != function_cls && val->cls != instancemethod_cls) { if (val->cls != function_cls && val->cls != instancemethod_cls) {
rewrite_args = NULL; rewrite_args = NULL;
REWRITE_ABORTED("");
} }
if (rewrite_args) { if (rewrite_args) {
...@@ -2239,11 +2306,13 @@ Box* callFunc(BoxedFunction* func, CallRewriteArgs* rewrite_args, ArgPassSpec ar ...@@ -2239,11 +2306,13 @@ Box* callFunc(BoxedFunction* func, CallRewriteArgs* rewrite_args, ArgPassSpec ar
if (argspec.has_starargs || argspec.has_kwargs || f->takes_kwargs || func->isGenerator) { if (argspec.has_starargs || argspec.has_kwargs || f->takes_kwargs || func->isGenerator) {
rewrite_args = NULL; rewrite_args = NULL;
REWRITE_ABORTED("");
} }
// These could be handled: // These could be handled:
if (argspec.num_keywords) { if (argspec.num_keywords) {
rewrite_args = NULL; rewrite_args = NULL;
REWRITE_ABORTED("");
} }
// TODO Should we guard on the CLFunction or the BoxedFunction? // TODO Should we guard on the CLFunction or the BoxedFunction?
...@@ -2328,10 +2397,12 @@ Box* callFunc(BoxedFunction* func, CallRewriteArgs* rewrite_args, ArgPassSpec ar ...@@ -2328,10 +2397,12 @@ Box* callFunc(BoxedFunction* func, CallRewriteArgs* rewrite_args, ArgPassSpec ar
std::vector<Box*, StlCompatAllocator<Box*>> unused_positional; std::vector<Box*, StlCompatAllocator<Box*>> unused_positional;
for (int i = positional_to_positional; i < argspec.num_args; i++) { for (int i = positional_to_positional; i < argspec.num_args; i++) {
rewrite_args = NULL; rewrite_args = NULL;
REWRITE_ABORTED("");
unused_positional.push_back(getArg(i, arg1, arg2, arg3, args)); unused_positional.push_back(getArg(i, arg1, arg2, arg3, args));
} }
for (int i = varargs_to_positional; i < varargs.size(); i++) { for (int i = varargs_to_positional; i < varargs.size(); i++) {
rewrite_args = NULL; rewrite_args = NULL;
REWRITE_ABORTED("");
unused_positional.push_back(varargs[i]); unused_positional.push_back(varargs[i]);
} }
...@@ -2785,6 +2856,7 @@ extern "C" Box* binopInternal(Box* lhs, Box* rhs, int op_type, bool inplace, Bin ...@@ -2785,6 +2856,7 @@ extern "C" Box* binopInternal(Box* lhs, Box* rhs, int op_type, bool inplace, Bin
if (rewrite_args) { if (rewrite_args) {
assert(rewrite_args->out_success == false); assert(rewrite_args->out_success == false);
rewrite_args = NULL; rewrite_args = NULL;
REWRITE_ABORTED("");
} }
std::string rop_name = getReverseOpName(op_type); std::string rop_name = getReverseOpName(op_type);
...@@ -2978,6 +3050,7 @@ Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs* rewrit ...@@ -2978,6 +3050,7 @@ Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs* rewrit
if (rewrite_args) { if (rewrite_args) {
assert(rewrite_args->out_success == false); assert(rewrite_args->out_success == false);
rewrite_args = NULL; rewrite_args = NULL;
REWRITE_ABORTED("");
} }
std::string rop_name = getReverseOpName(op_type); std::string rop_name = getReverseOpName(op_type);
...@@ -3182,25 +3255,34 @@ extern "C" void delitem(Box* target, Box* slice) { ...@@ -3182,25 +3255,34 @@ extern "C" void delitem(Box* target, Box* slice) {
} }
void Box::delattr(const std::string& attr, DelattrRewriteArgs* rewrite_args) { void Box::delattr(const std::string& attr, DelattrRewriteArgs* rewrite_args) {
// as soon as the hcls changes, the guard on hidden class won't pass. if (cls->instancesHaveHCAttrs()) {
HCAttrs* attrs = getAttrsPtr(); // as soon as the hcls changes, the guard on hidden class won't pass.
HiddenClass* hcls = attrs->hcls; HCAttrs* attrs = getHCAttrsPtr();
HiddenClass* new_hcls = hcls->delAttrToMakeHC(attr); HiddenClass* hcls = attrs->hcls;
HiddenClass* new_hcls = hcls->delAttrToMakeHC(attr);
// The order of attributes is pertained as delAttrToMakeHC constructs
// the new HiddenClass by invoking getOrMakeChild in the prevous order // The order of attributes is pertained as delAttrToMakeHC constructs
// of remaining attributes // the new HiddenClass by invoking getOrMakeChild in the prevous order
int num_attrs = hcls->attr_offsets.size(); // of remaining attributes
int offset = hcls->getOffset(attr); int num_attrs = hcls->attr_offsets.size();
assert(offset >= 0); int offset = hcls->getOffset(attr);
Box** start = attrs->attr_list->attrs; assert(offset >= 0);
memmove(start + offset, start + offset + 1, (num_attrs - offset - 1) * sizeof(Box*)); Box** start = attrs->attr_list->attrs;
memmove(start + offset, start + offset + 1, (num_attrs - offset - 1) * sizeof(Box*));
attrs->hcls = new_hcls;
// guarantee the size of the attr_list equals the number of attrs
int new_size = sizeof(HCAttrs::AttrList) + sizeof(Box*) * (num_attrs - 1);
attrs->attr_list = (HCAttrs::AttrList*)gc::gc_realloc(attrs->attr_list, new_size);
return;
}
attrs->hcls = new_hcls; if (cls->instancesHaveDictAttrs()) {
Py_FatalError("unimplemented");
}
// guarantee the size of the attr_list equals the number of attrs abort();
int new_size = sizeof(HCAttrs::AttrList) + sizeof(Box*) * (num_attrs - 1);
attrs->attr_list = (HCAttrs::AttrList*)gc::gc_realloc(attrs->attr_list, new_size);
} }
extern "C" void delattr_internal(Box* obj, const std::string& attr, bool allow_custom, extern "C" void delattr_internal(Box* obj, const std::string& attr, bool allow_custom,
...@@ -3332,13 +3414,14 @@ Box* typeNew(Box* _cls, Box* arg1, Box* arg2, Box** _args) { ...@@ -3332,13 +3414,14 @@ Box* typeNew(Box* _cls, Box* arg1, Box* arg2, Box** _args) {
BoxedClass* made; BoxedClass* made;
if (base->instancesHaveAttrs()) { if (base->instancesHaveDictAttrs() || base->instancesHaveHCAttrs()) {
made = new (cls) BoxedHeapClass(base, NULL, base->attrs_offset, base->tp_basicsize, true); made = new (cls) BoxedHeapClass(base, NULL, base->attrs_offset, base->tp_basicsize, true);
} else { } else {
assert(base->tp_basicsize % sizeof(void*) == 0); assert(base->tp_basicsize % sizeof(void*) == 0);
made = new (cls) BoxedHeapClass(base, NULL, base->tp_basicsize, base->tp_basicsize + sizeof(HCAttrs), true); made = new (cls) BoxedHeapClass(base, NULL, base->tp_basicsize, base->tp_basicsize + sizeof(HCAttrs), true);
} }
made->tp_dictoffset = base->tp_dictoffset;
made->giveAttr("__module__", boxString(getCurrentModule()->name())); made->giveAttr("__module__", boxString(getCurrentModule()->name()));
made->giveAttr("__doc__", None); made->giveAttr("__doc__", None);
...@@ -3373,6 +3456,7 @@ Box* typeCallInternal(BoxedFunction* f, CallRewriteArgs* rewrite_args, ArgPassSp ...@@ -3373,6 +3456,7 @@ Box* typeCallInternal(BoxedFunction* f, CallRewriteArgs* rewrite_args, ArgPassSp
// TODO shouldn't have to redo this argument handling here... // TODO shouldn't have to redo this argument handling here...
if (argspec.has_starargs) { if (argspec.has_starargs) {
rewrite_args = NULL; rewrite_args = NULL;
REWRITE_ABORTED("");
Box* starargs; Box* starargs;
if (argspec.num_args == 0) if (argspec.num_args == 0)
...@@ -3452,6 +3536,7 @@ Box* typeCallInternal(BoxedFunction* f, CallRewriteArgs* rewrite_args, ArgPassSp ...@@ -3452,6 +3536,7 @@ Box* typeCallInternal(BoxedFunction* f, CallRewriteArgs* rewrite_args, ArgPassSp
if (descr_r) { if (descr_r) {
new_attr = descr_r; new_attr = descr_r;
rewrite_args = NULL; rewrite_args = NULL;
REWRITE_ABORTED("");
} }
} }
} else { } else {
...@@ -3516,6 +3601,7 @@ Box* typeCallInternal(BoxedFunction* f, CallRewriteArgs* rewrite_args, ArgPassSp ...@@ -3516,6 +3601,7 @@ Box* typeCallInternal(BoxedFunction* f, CallRewriteArgs* rewrite_args, ArgPassSp
// ASSERT(cls->is_user_defined || cls == type_cls, "Does '%s' have a well-behaved __new__? if so, add to // ASSERT(cls->is_user_defined || cls == type_cls, "Does '%s' have a well-behaved __new__? if so, add to
// allowable_news, otherwise add to the blacklist in this assert", cls->tp_name); // allowable_news, otherwise add to the blacklist in this assert", cls->tp_name);
rewrite_args = NULL; rewrite_args = NULL;
REWRITE_ABORTED("");
} }
} }
...@@ -3800,7 +3886,7 @@ extern "C" Box* importStar(Box* _from_module, BoxedModule* to_module) { ...@@ -3800,7 +3886,7 @@ extern "C" Box* importStar(Box* _from_module, BoxedModule* to_module) {
return None; return None;
} }
HCAttrs* module_attrs = from_module->getAttrsPtr(); HCAttrs* module_attrs = from_module->getHCAttrsPtr();
for (auto& p : module_attrs->hcls->attr_offsets) { for (auto& p : module_attrs->hcls->attr_offsets) {
if (p.first[0] == '_') if (p.first[0] == '_')
continue; continue;
......
...@@ -349,8 +349,8 @@ extern "C" void boxGCHandler(GCVisitor* v, Box* b) { ...@@ -349,8 +349,8 @@ extern "C" void boxGCHandler(GCVisitor* v, Box* b) {
if (b->cls) { if (b->cls) {
v->visit(b->cls); v->visit(b->cls);
if (b->cls->instancesHaveAttrs()) { if (b->cls->instancesHaveHCAttrs()) {
HCAttrs* attrs = b->getAttrsPtr(); HCAttrs* attrs = b->getHCAttrsPtr();
v->visit(attrs->hcls); v->visit(attrs->hcls);
int nattrs = attrs->hcls->attr_offsets.size(); int nattrs = attrs->hcls->attr_offsets.size();
...@@ -361,6 +361,10 @@ extern "C" void boxGCHandler(GCVisitor* v, Box* b) { ...@@ -361,6 +361,10 @@ extern "C" void boxGCHandler(GCVisitor* v, Box* b) {
v->visitRange((void**)&attr_list->attrs[0], (void**)&attr_list->attrs[nattrs]); v->visitRange((void**)&attr_list->attrs[0], (void**)&attr_list->attrs[nattrs]);
} }
} }
if (b->cls->instancesHaveDictAttrs()) {
RELEASE_ASSERT(0, "Shouldn't all of these objects be conservatively scanned?");
}
} else { } else {
assert(type_cls == NULL || b == type_cls); assert(type_cls == NULL || b == type_cls);
} }
...@@ -776,7 +780,7 @@ private: ...@@ -776,7 +780,7 @@ private:
Box* b; Box* b;
public: public:
AttrWrapper(Box* b) : b(b) {} AttrWrapper(Box* b) : b(b) { assert(b->cls->instancesHaveHCAttrs()); }
DEFAULT_CLASS(attrwrapper_cls); DEFAULT_CLASS(attrwrapper_cls);
...@@ -829,7 +833,7 @@ public: ...@@ -829,7 +833,7 @@ public:
std::ostringstream os(""); std::ostringstream os("");
os << "attrwrapper({"; os << "attrwrapper({";
HCAttrs* attrs = self->b->getAttrsPtr(); HCAttrs* attrs = self->b->getHCAttrsPtr();
bool first = true; bool first = true;
for (const auto& p : attrs->hcls->attr_offsets) { for (const auto& p : attrs->hcls->attr_offsets) {
if (!first) if (!first)
...@@ -859,7 +863,7 @@ public: ...@@ -859,7 +863,7 @@ public:
BoxedList* rtn = new BoxedList(); BoxedList* rtn = new BoxedList();
HCAttrs* attrs = self->b->getAttrsPtr(); HCAttrs* attrs = self->b->getHCAttrsPtr();
for (const auto& p : attrs->hcls->attr_offsets) { for (const auto& p : attrs->hcls->attr_offsets) {
BoxedTuple* t = new BoxedTuple({ boxString(p.first), attrs->attr_list->attrs[p.second] }); BoxedTuple* t = new BoxedTuple({ boxString(p.first), attrs->attr_list->attrs[p.second] });
listAppend(rtn, t); listAppend(rtn, t);
...@@ -869,7 +873,7 @@ public: ...@@ -869,7 +873,7 @@ public:
}; };
Box* makeAttrWrapper(Box* b) { Box* makeAttrWrapper(Box* b) {
assert(b->cls->instancesHaveAttrs()); assert(b->cls->instancesHaveHCAttrs());
return new AttrWrapper(b); return new AttrWrapper(b);
} }
...@@ -908,8 +912,8 @@ Box* objectStr(Box* obj) { ...@@ -908,8 +912,8 @@ Box* objectStr(Box* obj) {
// Added as parameter because it should typically be available // Added as parameter because it should typically be available
inline void initUserAttrs(Box* obj, BoxedClass* cls) { inline void initUserAttrs(Box* obj, BoxedClass* cls) {
assert(obj->cls == cls); assert(obj->cls == cls);
if (cls->attrs_offset) { if (cls->instancesHaveHCAttrs()) {
HCAttrs* attrs = obj->getAttrsPtr(); HCAttrs* attrs = obj->getHCAttrsPtr();
attrs = new ((void*)attrs) HCAttrs(); attrs = new ((void*)attrs) HCAttrs();
} }
} }
......
...@@ -199,7 +199,8 @@ public: ...@@ -199,7 +199,8 @@ public:
// Analogous to tp_dictoffset // Analogous to tp_dictoffset
const int attrs_offset; const int attrs_offset;
bool instancesHaveAttrs() { return attrs_offset != 0; } bool instancesHaveHCAttrs() { return attrs_offset != 0; }
bool instancesHaveDictAttrs() { return tp_dictoffset != 0; }
// Whether this class object is constant or not, ie whether or not class-level // Whether this class object is constant or not, ie whether or not class-level
// attributes can be changed or added. // attributes can be changed or added.
......
#include <Python.h> #include <Python.h>
#include <stddef.h> /* For offsetof */
typedef struct { typedef struct {
PyObject_HEAD PyObject_HEAD;
PyObject* dict;
int n; int n;
} slots_tester_object; } slots_tester_object;
...@@ -252,7 +255,7 @@ static PyTypeObject slots_tester_map= { ...@@ -252,7 +255,7 @@ static PyTypeObject slots_tester_map= {
0, /* tp_dict */ 0, /* tp_dict */
0, /* tp_descr_get */ 0, /* tp_descr_get */
0, /* tp_descr_set */ 0, /* tp_descr_set */
0, /* tp_dictoffset */ offsetof(slots_tester_object, dict), /* tp_dictoffset */
0, /* tp_init */ 0, /* tp_init */
0, /* tp_alloc */ 0, /* tp_alloc */
slots_tester_new, /* tp_new */ slots_tester_new, /* tp_new */
......
...@@ -88,3 +88,27 @@ try: ...@@ -88,3 +88,27 @@ try:
pass pass
except TypeError, e: except TypeError, e:
print e print e
try:
slots_test.SlotsTesterSeq(5).foo = 1
except AttributeError, e:
print e
try:
print slots_test.SlotsTesterSeq(5).__dict__
except AttributeError, e:
print e
c = C3(5)
c.foo = 1
print c.foo
print c.__dict__.items()
s = slots_test.SlotsTesterMap(6)
s.bar = 2
print s.bar
print hasattr(s, "bar"), hasattr(s, "foo")
try:
print s.__dict__
except AttributeError, e:
print e
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