Commit d1c5d853 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge branch 'getattr'

Things are getting pretty messy, but it's an incremental step towards doing things more
like CPython which should ultimately make things simpler.

The use of the tp_getattro slots (even though they're the CAPI slots) seems to lead to
about a ~7% improvement in interpreter-only speed.
parents c5f22166 b42de323
...@@ -737,12 +737,15 @@ void Assembler::cmp(Indirect mem, Immediate imm) { ...@@ -737,12 +737,15 @@ void Assembler::cmp(Indirect mem, Immediate imm) {
emitRex(rex); emitRex(rex);
emitByte(0x81); emitByte(0x81);
assert(-0x80 <= mem.offset && mem.offset < 0x80);
if (mem.offset == 0) { if (mem.offset == 0) {
emitModRM(0b00, 7, src_idx); emitModRM(0b00, 7, src_idx);
} else { } else if (-0x80 <= mem.offset && mem.offset < 0x80) {
emitModRM(0b01, 7, src_idx); emitModRM(0b01, 7, src_idx);
emitByte(mem.offset); emitByte(mem.offset);
} else {
assert((-1L << 31) <= mem.offset && mem.offset < (1L << 31) - 1);
emitModRM(0b10, 7, src_idx);
emitInt(mem.offset, 4);
} }
emitInt(val, 4); emitInt(val, 4);
......
...@@ -25,6 +25,7 @@ namespace pyston { ...@@ -25,6 +25,7 @@ namespace pyston {
static const std::string _new_str("__new__"); static const std::string _new_str("__new__");
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__");
typedef int (*update_callback)(PyTypeObject*, void*);
extern "C" void conservativeGCHandler(GCVisitor* v, Box* b) noexcept { extern "C" void conservativeGCHandler(GCVisitor* v, Box* b) noexcept {
v->visitPotentialRange((void* const*)b, (void* const*)((char*)b + b->cls->tp_basicsize)); v->visitPotentialRange((void* const*)b, (void* const*)((char*)b + b->cls->tp_basicsize));
...@@ -142,6 +143,24 @@ static PyObject* wrap_next(PyObject* self, PyObject* args, void* wrapped) { ...@@ -142,6 +143,24 @@ static PyObject* wrap_next(PyObject* self, PyObject* args, void* wrapped) {
return res; return res;
} }
static PyObject* wrap_descr_get(PyObject* self, PyObject* args, void* wrapped) noexcept {
descrgetfunc func = (descrgetfunc)wrapped;
PyObject* obj;
PyObject* type = NULL;
if (!PyArg_UnpackTuple(args, "", 1, 2, &obj, &type))
return NULL;
if (obj == Py_None)
obj = NULL;
if (type == Py_None)
type = NULL;
if (type == NULL && obj == NULL) {
PyErr_SetString(PyExc_TypeError, "__get__(None, None) is invalid");
return NULL;
}
return (*func)(self, obj, type);
}
static PyObject* wrap_coercefunc(PyObject* self, PyObject* args, void* wrapped) noexcept { static PyObject* wrap_coercefunc(PyObject* self, PyObject* args, void* wrapped) noexcept {
coercion func = (coercion)wrapped; coercion func = (coercion)wrapped;
PyObject* other, *res; PyObject* other, *res;
...@@ -676,6 +695,25 @@ static PyObject* slot_tp_iternext(PyObject* self) noexcept { ...@@ -676,6 +695,25 @@ static PyObject* slot_tp_iternext(PyObject* self) noexcept {
return call_method(self, "next", &next_str, "()"); return call_method(self, "next", &next_str, "()");
} }
static PyObject* slot_tp_descr_get(PyObject* self, PyObject* obj, PyObject* type) noexcept {
PyTypeObject* tp = Py_TYPE(self);
PyObject* get;
get = typeLookup(tp, "__get__", NULL);
if (get == NULL) {
/* Avoid further slowdowns */
if (tp->tp_descr_get == slot_tp_descr_get)
tp->tp_descr_get = NULL;
Py_INCREF(self);
return self;
}
if (obj == NULL)
obj = Py_None;
if (type == NULL)
type = Py_None;
return PyObject_CallFunctionObjArgs(get, self, obj, type, NULL);
}
static PyObject* slot_tp_getattro(PyObject* self, PyObject* name) noexcept { static PyObject* slot_tp_getattro(PyObject* self, PyObject* name) noexcept {
static PyObject* getattribute_str = NULL; static PyObject* getattribute_str = NULL;
return call_method(self, "__getattribute__", &getattribute_str, "(O)", name); return call_method(self, "__getattribute__", &getattribute_str, "(O)", name);
...@@ -707,7 +745,7 @@ static PyObject* call_attribute(PyObject* self, PyObject* attr, PyObject* name) ...@@ -707,7 +745,7 @@ static PyObject* call_attribute(PyObject* self, PyObject* attr, PyObject* name)
attr = descr; attr = descr;
} }
try { try {
res = runtimeCall(attr, ArgPassSpec(1, 0, true, true), name, NULL, NULL, NULL, NULL); res = runtimeCall(attr, ArgPassSpec(1, 0, false, false), name, NULL, NULL, NULL, NULL);
} catch (ExcInfo e) { } catch (ExcInfo e) {
setCAPIException(e); setCAPIException(e);
Py_XDECREF(descr); Py_XDECREF(descr);
...@@ -719,8 +757,6 @@ static PyObject* call_attribute(PyObject* self, PyObject* attr, PyObject* name) ...@@ -719,8 +757,6 @@ static PyObject* call_attribute(PyObject* self, PyObject* attr, PyObject* name)
static PyObject* slot_tp_getattr_hook(PyObject* self, PyObject* name) noexcept { static PyObject* slot_tp_getattr_hook(PyObject* self, PyObject* name) noexcept {
PyObject* getattr, *getattribute, * res = NULL; PyObject* getattr, *getattribute, * res = NULL;
static PyObject* getattribute_str = NULL;
static PyObject* getattr_str = NULL;
/* speed hack: we could use lookup_maybe, but that would resolve the /* speed hack: we could use lookup_maybe, but that would resolve the
method fully for each attribute lookup for classes with method fully for each attribute lookup for classes with
...@@ -746,13 +782,9 @@ static PyObject* slot_tp_getattr_hook(PyObject* self, PyObject* name) noexcept { ...@@ -746,13 +782,9 @@ static PyObject* slot_tp_getattr_hook(PyObject* self, PyObject* name) noexcept {
} else { } else {
res = call_attribute(self, getattribute, name); res = call_attribute(self, getattribute, name);
} }
if (res == NULL) { if (res == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) {
try { PyErr_Clear();
res = runtimeCall(getattr, ArgPassSpec(2, 0, true, true), self, name, NULL, NULL, NULL); res = call_attribute(self, getattr, name);
} catch (ExcInfo e) {
setCAPIException(e);
return NULL;
}
} }
return res; return res;
} }
...@@ -1197,7 +1229,8 @@ static void** slotptr(BoxedClass* type, int offset) noexcept { ...@@ -1197,7 +1229,8 @@ static void** slotptr(BoxedClass* type, int offset) noexcept {
ETSLOT(NAME, as_number.SLOT, FUNCTION, wrap_binaryfunc_r, "x." NAME "(y) <==> " DOC) ETSLOT(NAME, as_number.SLOT, FUNCTION, wrap_binaryfunc_r, "x." NAME "(y) <==> " DOC)
static slotdef slotdefs[] static slotdef slotdefs[]
= { TPSLOT("__getattr__", tp_getattr, NULL, NULL, ""), = { TPSLOT("__getattribute__", tp_getattr, NULL, NULL, ""),
TPSLOT("__getattr__", tp_getattr, NULL, NULL, ""),
TPSLOT("__setattr__", tp_setattr, NULL, NULL, ""), TPSLOT("__setattr__", tp_setattr, NULL, NULL, ""),
TPSLOT("__delattr__", tp_setattr, NULL, NULL, ""), TPSLOT("__delattr__", tp_setattr, NULL, NULL, ""),
...@@ -1207,6 +1240,8 @@ static slotdef slotdefs[] ...@@ -1207,6 +1240,8 @@ static slotdef slotdefs[]
PyWrapperFlag_KEYWORDS), PyWrapperFlag_KEYWORDS),
TPSLOT("__str__", tp_str, slot_tp_str, wrap_unaryfunc, "x.__str__() <==> str(x)"), TPSLOT("__str__", tp_str, slot_tp_str, wrap_unaryfunc, "x.__str__() <==> str(x)"),
TPSLOT("__getattribute__", tp_getattro, slot_tp_getattr_hook, wrap_binaryfunc,
"x.__getattribute__('name') <==> x.name"),
TPSLOT("__getattr__", tp_getattro, slot_tp_getattr_hook, NULL, ""), TPSLOT("__getattr__", tp_getattro, slot_tp_getattr_hook, NULL, ""),
TPSLOT("__setattr__", tp_setattro, slot_tp_setattro, wrap_setattr, TPSLOT("__setattr__", tp_setattro, slot_tp_setattro, wrap_setattr,
"x.__setattr__('name', value) <==> x.name = value"), "x.__setattr__('name', value) <==> x.name = value"),
...@@ -1221,6 +1256,7 @@ static slotdef slotdefs[] ...@@ -1221,6 +1256,7 @@ static slotdef slotdefs[]
TPSLOT("__iter__", tp_iter, slot_tp_iter, wrap_unaryfunc, "x.__iter__() <==> iter(x)"), TPSLOT("__iter__", tp_iter, slot_tp_iter, wrap_unaryfunc, "x.__iter__() <==> iter(x)"),
TPSLOT("next", tp_iternext, slot_tp_iternext, wrap_next, "x.next() -> the next value, or raise StopIteration"), TPSLOT("next", tp_iternext, slot_tp_iternext, wrap_next, "x.next() -> the next value, or raise StopIteration"),
TPSLOT("__get__", tp_descr_get, slot_tp_descr_get, wrap_descr_get, "descr.__get__(obj[, type]) -> value"),
FLSLOT("__init__", tp_init, slot_tp_init, (wrapperfunc)wrap_init, "x.__init__(...) initializes x; " FLSLOT("__init__", tp_init, slot_tp_init, (wrapperfunc)wrap_init, "x.__init__(...) initializes x; "
"see help(type(x)) for signature", "see help(type(x)) for signature",
...@@ -1461,18 +1497,55 @@ static const slotdef* update_one_slot(BoxedClass* type, const slotdef* p) noexce ...@@ -1461,18 +1497,55 @@ static const slotdef* update_one_slot(BoxedClass* type, const slotdef* p) noexce
return p; return p;
} }
bool update_slot(BoxedClass* self, const std::string& attr) noexcept { /* In the type, update the slots whose slotdefs are gathered in the pp array.
bool updated = false; This is a callback for update_subclasses(). */
for (const slotdef& p : slotdefs) { static int update_slots_callback(PyTypeObject* type, void* data) noexcept {
if (!p.name) slotdef** pp = (slotdef**)data;
continue;
if (p.name == attr) { for (; *pp; pp++)
// TODO update subclasses; update_one_slot(type, *pp);
update_one_slot(self, &p); return 0;
updated = true; }
}
static int update_subclasses(PyTypeObject* type, PyObject* name, update_callback callback, void* data) noexcept;
static int recurse_down_subclasses(PyTypeObject* type, PyObject* name, update_callback callback, void* data) noexcept;
bool update_slot(BoxedClass* type, const std::string& attr) noexcept {
slotdef* ptrs[MAX_EQUIV];
slotdef* p;
slotdef** pp;
int offset;
/* Clear the VALID_VERSION flag of 'type' and all its
subclasses. This could possibly be unified with the
update_subclasses() recursion below, but carefully:
they each have their own conditions on which to stop
recursing into subclasses. */
PyType_Modified(type);
init_slotdefs();
pp = ptrs;
for (p = slotdefs; p->name; p++) {
/* XXX assume name is interned! */
if (p->name == attr)
*pp++ = p;
} }
return updated; *pp = NULL;
for (pp = ptrs; *pp; pp++) {
p = *pp;
offset = p->offset;
while (p > slotdefs && (p - 1)->offset == offset)
--p;
*pp = p;
}
if (ptrs[0] == NULL)
return false; /* Not an attribute that affects any slots */
int r = update_subclasses(type, new BoxedString(attr), update_slots_callback, (void*)ptrs);
// TODO this is supposed to be a CAPI function!
if (r)
throwCAPIException();
return true;
} }
void fixup_slot_dispatchers(BoxedClass* self) noexcept { void fixup_slot_dispatchers(BoxedClass* self) noexcept {
...@@ -1483,6 +1556,40 @@ void fixup_slot_dispatchers(BoxedClass* self) noexcept { ...@@ -1483,6 +1556,40 @@ void fixup_slot_dispatchers(BoxedClass* self) noexcept {
p = update_one_slot(self, p); p = update_one_slot(self, p);
} }
static int update_subclasses(PyTypeObject* type, PyObject* name, update_callback callback, void* data) noexcept {
if (callback(type, data) < 0)
return -1;
return recurse_down_subclasses(type, name, callback, data);
}
static int recurse_down_subclasses(PyTypeObject* type, PyObject* name, update_callback callback, void* data) noexcept {
PyTypeObject* subclass;
PyObject* ref, *subclasses, *dict;
Py_ssize_t i, n;
subclasses = type->tp_subclasses;
if (subclasses == NULL)
return 0;
assert(PyList_Check(subclasses));
n = PyList_GET_SIZE(subclasses);
for (i = 0; i < n; i++) {
ref = PyList_GET_ITEM(subclasses, i);
assert(PyWeakref_CheckRef(ref));
subclass = (PyTypeObject*)PyWeakref_GET_OBJECT(ref);
assert(subclass != NULL);
if ((PyObject*)subclass == Py_None)
continue;
assert(PyType_Check(subclass));
/* Avoid recursing down into unaffected classes */
dict = subclass->tp_dict;
if (dict != NULL && PyDict_Check(dict) && PyDict_GetItem(dict, name) != NULL)
continue;
if (update_subclasses(subclass, name, callback, data) < 0)
return -1;
}
return 0;
}
static PyObject* tp_new_wrapper(PyTypeObject* self, BoxedTuple* args, Box* kwds) noexcept { static PyObject* tp_new_wrapper(PyTypeObject* self, BoxedTuple* args, Box* kwds) noexcept {
RELEASE_ASSERT(isSubclass(self->cls, type_cls), ""); RELEASE_ASSERT(isSubclass(self->cls, type_cls), "");
...@@ -1509,7 +1616,7 @@ static void add_tp_new_wrapper(BoxedClass* type) noexcept { ...@@ -1509,7 +1616,7 @@ static void add_tp_new_wrapper(BoxedClass* type) noexcept {
new BoxedCApiFunction(METH_VARARGS | METH_KEYWORDS, type, "__new__", (PyCFunction)tp_new_wrapper)); new BoxedCApiFunction(METH_VARARGS | METH_KEYWORDS, type, "__new__", (PyCFunction)tp_new_wrapper));
} }
static void add_operators(BoxedClass* cls) noexcept { void add_operators(BoxedClass* cls) noexcept {
init_slotdefs(); init_slotdefs();
for (const slotdef& p : slotdefs) { for (const slotdef& p : slotdefs) {
...@@ -2335,6 +2442,52 @@ static void inherit_slots(PyTypeObject* type, PyTypeObject* base) noexcept { ...@@ -2335,6 +2442,52 @@ static void inherit_slots(PyTypeObject* type, PyTypeObject* base) noexcept {
} }
} }
static int add_subclass(PyTypeObject* base, PyTypeObject* type) noexcept {
Py_ssize_t i;
int result;
PyObject* list, *ref, *newobj;
list = base->tp_subclasses;
if (list == NULL) {
base->tp_subclasses = list = PyList_New(0);
if (list == NULL)
return -1;
}
assert(PyList_Check(list));
newobj = PyWeakref_NewRef((PyObject*)type, NULL);
i = PyList_GET_SIZE(list);
while (--i >= 0) {
ref = PyList_GET_ITEM(list, i);
assert(PyWeakref_CheckRef(ref));
if (PyWeakref_GET_OBJECT(ref) == Py_None)
return PyList_SetItem(list, i, newobj);
}
result = PyList_Append(list, newobj);
Py_DECREF(newobj);
return result;
}
static void remove_subclass(PyTypeObject* base, PyTypeObject* type) noexcept {
Py_ssize_t i;
PyObject* list, *ref;
list = base->tp_subclasses;
if (list == NULL) {
return;
}
assert(PyList_Check(list));
i = PyList_GET_SIZE(list);
while (--i >= 0) {
ref = PyList_GET_ITEM(list, i);
assert(PyWeakref_CheckRef(ref));
if (PyWeakref_GET_OBJECT(ref) == (PyObject*)type) {
/* this can't fail, right? */
PySequence_DelItem(list, i);
return;
}
}
}
// commonClassSetup is for the common code between PyType_Ready (which is just for extension classes) // commonClassSetup is for the common code between PyType_Ready (which is just for extension classes)
// and our internal type-creation endpoints (BoxedClass::BoxedClass()). // and our internal type-creation endpoints (BoxedClass::BoxedClass()).
// TODO: Move more of the duplicated logic into here. // TODO: Move more of the duplicated logic into here.
...@@ -2346,6 +2499,12 @@ void commonClassSetup(BoxedClass* cls) { ...@@ -2346,6 +2499,12 @@ void commonClassSetup(BoxedClass* cls) {
cls->tp_bases = new BoxedTuple({}); cls->tp_bases = new BoxedTuple({});
} }
/* Link into each base class's list of subclasses */
for (PyObject* b : static_cast<BoxedTuple*>(cls->tp_bases)->elts) {
if (PyType_Check(b) && add_subclass((PyTypeObject*)b, cls) < 0)
throwCAPIException();
}
/* Calculate method resolution order */ /* Calculate method resolution order */
if (mro_internal(cls) < 0) if (mro_internal(cls) < 0)
throwCAPIException(); throwCAPIException();
......
...@@ -22,6 +22,7 @@ namespace pyston { ...@@ -22,6 +22,7 @@ namespace pyston {
// Returns if a slot was updated // Returns if a slot was updated
bool update_slot(BoxedClass* self, const std::string& attr) noexcept; bool update_slot(BoxedClass* self, const std::string& attr) noexcept;
void add_operators(BoxedClass* self) noexcept;
void fixup_slot_dispatchers(BoxedClass* self) noexcept; void fixup_slot_dispatchers(BoxedClass* self) noexcept;
void commonClassSetup(BoxedClass* cls); void commonClassSetup(BoxedClass* cls);
......
...@@ -98,6 +98,7 @@ public: ...@@ -98,6 +98,7 @@ public:
DEFAULT_CLASS(wrapperdescr_cls); DEFAULT_CLASS(wrapperdescr_cls);
static Box* __get__(BoxedWrapperDescriptor* self, Box* inst, Box* owner); static Box* __get__(BoxedWrapperDescriptor* self, Box* inst, Box* owner);
static Box* __call__(BoxedWrapperDescriptor* descr, PyObject* self, BoxedTuple* args, Box** _args);
}; };
class BoxedWrapperObject : public Box { class BoxedWrapperObject : public Box {
......
...@@ -93,12 +93,6 @@ void setupBool() { ...@@ -93,12 +93,6 @@ void setupBool() {
bool_cls->giveAttr("__xor__", new BoxedFunction(boxRTFunction((void*)boolXor, BOXED_BOOL, 2))); bool_cls->giveAttr("__xor__", new BoxedFunction(boxRTFunction((void*)boolXor, BOXED_BOOL, 2)));
bool_cls->freeze(); bool_cls->freeze();
True = new BoxedBool(true);
False = new BoxedBool(false);
gc::registerPermanentRoot(True);
gc::registerPermanentRoot(False);
} }
void teardownBool() { void teardownBool() {
......
...@@ -194,6 +194,7 @@ public: ...@@ -194,6 +194,7 @@ public:
BoxedSysFlags() { BoxedSysFlags() {
auto zero = boxInt(0); auto zero = boxInt(0);
assert(zero);
division_warning = zero; division_warning = zero;
bytes_warning = zero; bytes_warning = zero;
no_user_site = zero; no_user_site = zero;
...@@ -297,8 +298,8 @@ void setupSys() { ...@@ -297,8 +298,8 @@ void setupSys() {
sys_module->giveAttr("maxint", boxInt(PYSTON_INT_MAX)); sys_module->giveAttr("maxint", boxInt(PYSTON_INT_MAX));
sys_flags_cls = BoxedHeapClass::create(type_cls, object_cls, BoxedSysFlags::gcHandler, 0, 0, sizeof(BoxedSysFlags), sys_flags_cls = new BoxedHeapClass(object_cls, BoxedSysFlags::gcHandler, 0, 0, sizeof(BoxedSysFlags), false,
false, "flags"); new BoxedString("flags"));
sys_flags_cls->giveAttr("__new__", sys_flags_cls->giveAttr("__new__",
new BoxedFunction(boxRTFunction((void*)BoxedSysFlags::__new__, UNKNOWN, 1, 0, true, true))); new BoxedFunction(boxRTFunction((void*)BoxedSysFlags::__new__, UNKNOWN, 1, 0, true, true)));
#define ADD(name) \ #define ADD(name) \
...@@ -309,6 +310,7 @@ void setupSys() { ...@@ -309,6 +310,7 @@ void setupSys() {
ADD(no_user_site); ADD(no_user_site);
#undef ADD #undef ADD
sys_flags_cls->tp_mro = new BoxedTuple({ sys_flags_cls, object_cls });
sys_flags_cls->freeze(); sys_flags_cls->freeze();
sys_module->giveAttr("flags", new BoxedSysFlags()); sys_module->giveAttr("flags", new BoxedSysFlags());
...@@ -324,5 +326,6 @@ void setupSysEnd() { ...@@ -324,5 +326,6 @@ void setupSysEnd() {
PyLt()); PyLt());
sys_module->giveAttr("builtin_module_names", new BoxedTuple(std::move(builtin_module_names))); sys_module->giveAttr("builtin_module_names", new BoxedTuple(std::move(builtin_module_names)));
sys_flags_cls->finishInitialization();
} }
} }
...@@ -88,6 +88,19 @@ Box* BoxedWrapperDescriptor::__get__(BoxedWrapperDescriptor* self, Box* inst, Bo ...@@ -88,6 +88,19 @@ Box* BoxedWrapperDescriptor::__get__(BoxedWrapperDescriptor* self, Box* inst, Bo
return new BoxedWrapperObject(self, inst); return new BoxedWrapperObject(self, inst);
} }
Box* BoxedWrapperDescriptor::__call__(BoxedWrapperDescriptor* descr, PyObject* self, BoxedTuple* args, Box** _args) {
RELEASE_ASSERT(descr->cls == wrapperdescr_cls, "");
BoxedDict* kw = static_cast<BoxedDict*>(_args[0]);
if (!isSubclass(self->cls, descr->type))
raiseExcHelper(TypeError, "descriptor '' requires a '%s' object but received a '%s'",
getFullNameOfClass(descr->type).c_str(), getFullTypeName(self).c_str());
auto wrapper = new BoxedWrapperObject(descr, self);
return BoxedWrapperObject::__call__(wrapper, args, kw);
}
extern "C" void _PyErr_BadInternalCall(const char* filename, int lineno) noexcept { extern "C" void _PyErr_BadInternalCall(const char* filename, int lineno) noexcept {
Py_FatalError("unimplemented"); Py_FatalError("unimplemented");
} }
...@@ -264,12 +277,11 @@ extern "C" PyObject* PyObject_GetAttr(PyObject* o, PyObject* attr_name) noexcept ...@@ -264,12 +277,11 @@ extern "C" PyObject* PyObject_GetAttr(PyObject* o, PyObject* attr_name) noexcept
} }
extern "C" PyObject* PyObject_GenericGetAttr(PyObject* o, PyObject* name) noexcept { extern "C" PyObject* PyObject_GenericGetAttr(PyObject* o, PyObject* name) noexcept {
try { Box* r = getattrInternalGeneric(o, static_cast<BoxedString*>(name)->s.c_str(), NULL, false, false, NULL, NULL);
return getattr(o, static_cast<BoxedString*>(name)->s.c_str()); if (!r)
} catch (ExcInfo e) { PyErr_Format(PyExc_AttributeError, "'%.50s' object has no attribute '%.400s'", o->cls->tp_name,
setCAPIException(e); PyString_AS_STRING(name));
return NULL; return r;
}
} }
extern "C" PyObject* _PyObject_GenericGetAttrWithDict(PyObject* obj, PyObject* name, PyObject* dict) noexcept { extern "C" PyObject* _PyObject_GenericGetAttrWithDict(PyObject* obj, PyObject* name, PyObject* dict) noexcept {
...@@ -1279,9 +1291,6 @@ static Box* methodGetDoc(Box* b, void*) { ...@@ -1279,9 +1291,6 @@ static Box* methodGetDoc(Box* b, void*) {
} }
void setupCAPI() { void setupCAPI() {
capifunc_cls
= BoxedHeapClass::create(type_cls, object_cls, NULL, 0, 0, sizeof(BoxedCApiFunction), false, "capifunc");
capifunc_cls->giveAttr("__repr__", capifunc_cls->giveAttr("__repr__",
new BoxedFunction(boxRTFunction((void*)BoxedCApiFunction::__repr__, UNKNOWN, 1))); new BoxedFunction(boxRTFunction((void*)BoxedCApiFunction::__repr__, UNKNOWN, 1)));
...@@ -1291,8 +1300,6 @@ void setupCAPI() { ...@@ -1291,8 +1300,6 @@ void setupCAPI() {
capifunc_cls->freeze(); capifunc_cls->freeze();
method_cls
= BoxedHeapClass::create(type_cls, object_cls, NULL, 0, 0, sizeof(BoxedMethodDescriptor), false, "method");
method_cls->giveAttr("__get__", method_cls->giveAttr("__get__",
new BoxedFunction(boxRTFunction((void*)BoxedMethodDescriptor::__get__, UNKNOWN, 3))); new BoxedFunction(boxRTFunction((void*)BoxedMethodDescriptor::__get__, UNKNOWN, 3)));
method_cls->giveAttr("__call__", new BoxedFunction(boxRTFunction((void*)BoxedMethodDescriptor::__call__, UNKNOWN, 2, method_cls->giveAttr("__call__", new BoxedFunction(boxRTFunction((void*)BoxedMethodDescriptor::__call__, UNKNOWN, 2,
...@@ -1300,14 +1307,12 @@ void setupCAPI() { ...@@ -1300,14 +1307,12 @@ void setupCAPI() {
method_cls->giveAttr("__doc__", new (pyston_getset_cls) BoxedGetsetDescriptor(methodGetDoc, NULL, NULL)); method_cls->giveAttr("__doc__", new (pyston_getset_cls) BoxedGetsetDescriptor(methodGetDoc, NULL, NULL));
method_cls->freeze(); method_cls->freeze();
wrapperdescr_cls = BoxedHeapClass::create(type_cls, object_cls, NULL, 0, 0, sizeof(BoxedWrapperDescriptor), false,
"wrapper_descriptor");
wrapperdescr_cls->giveAttr("__get__", wrapperdescr_cls->giveAttr("__get__",
new BoxedFunction(boxRTFunction((void*)BoxedWrapperDescriptor::__get__, UNKNOWN, 3))); new BoxedFunction(boxRTFunction((void*)BoxedWrapperDescriptor::__get__, UNKNOWN, 3)));
wrapperdescr_cls->giveAttr("__call__", new BoxedFunction(boxRTFunction((void*)BoxedWrapperDescriptor::__call__,
UNKNOWN, 2, 0, true, true)));
wrapperdescr_cls->freeze(); wrapperdescr_cls->freeze();
wrapperobject_cls
= BoxedHeapClass::create(type_cls, object_cls, NULL, 0, 0, sizeof(BoxedWrapperObject), false, "method-wrapper");
wrapperobject_cls->giveAttr( wrapperobject_cls->giveAttr(
"__call__", new BoxedFunction(boxRTFunction((void*)BoxedWrapperObject::__call__, UNKNOWN, 1, 0, true, true))); "__call__", new BoxedFunction(boxRTFunction((void*)BoxedWrapperObject::__call__, UNKNOWN, 1, 0, true, true)));
wrapperobject_cls->freeze(); wrapperobject_cls->freeze();
......
...@@ -1103,8 +1103,37 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, const ...@@ -1103,8 +1103,37 @@ Box* dataDescriptorInstanceSpecialCases(GetattrRewriteArgs* rewrite_args, const
return NULL; return NULL;
} }
inline Box* getclsattr_internal(Box* obj, const std::string& attr, GetattrRewriteArgs* rewrite_args) { Box* getattrInternalEx(Box* obj, const std::string& attr, GetattrRewriteArgs* rewrite_args, bool cls_only,
return getattrInternalGeneral(obj, attr, rewrite_args, bool for_call, Box** bind_obj_out, RewriterVar** r_bind_obj_out) {
if (!cls_only) {
BoxedClass* cls = obj->cls;
if (obj->cls->tp_getattro && obj->cls->tp_getattro != PyObject_GenericGetAttr) {
Box* r = obj->cls->tp_getattro(obj, new BoxedString(attr));
if (!r)
throwCAPIException();
return r;
}
if (obj->cls->tp_getattr) {
Box* r = obj->cls->tp_getattr(obj, const_cast<char*>(attr.c_str()));
if (!r)
throwCAPIException();
return r;
}
// We could also use the old invalidation-based approach here:
if (rewrite_args) {
auto r_cls = rewrite_args->obj->getAttr(offsetof(Box, cls));
r_cls->addAttrGuard(offsetof(BoxedClass, tp_getattr), (uint64_t)obj->cls->tp_getattr);
r_cls->addAttrGuard(offsetof(BoxedClass, tp_getattro), (uint64_t)obj->cls->tp_getattro);
}
}
return getattrInternalGeneric(obj, attr, rewrite_args, cls_only, for_call, bind_obj_out, r_bind_obj_out);
}
inline Box* getclsattrInternal(Box* obj, const std::string& attr, GetattrRewriteArgs* rewrite_args) {
return getattrInternalEx(obj, attr, rewrite_args,
/* cls_only */ true, /* cls_only */ true,
/* for_call */ false, NULL, NULL); /* for_call */ false, NULL, NULL);
} }
...@@ -1121,7 +1150,7 @@ extern "C" Box* getclsattr(Box* obj, const char* attr) { ...@@ -1121,7 +1150,7 @@ extern "C" Box* getclsattr(Box* obj, const char* attr) {
if (rewriter.get()) { if (rewriter.get()) {
//rewriter->trap(); //rewriter->trap();
GetattrRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0)); GetattrRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0));
gotten = getclsattr_internal(obj, attr, &rewrite_args, NULL); gotten = getclsattrInternal(obj, attr, &rewrite_args, NULL);
if (rewrite_args.out_success && gotten) { if (rewrite_args.out_success && gotten) {
rewrite_args.out_rtn.move(-1); rewrite_args.out_rtn.move(-1);
...@@ -1134,7 +1163,7 @@ extern "C" Box* getclsattr(Box* obj, const char* attr) { ...@@ -1134,7 +1163,7 @@ extern "C" Box* getclsattr(Box* obj, const char* attr) {
if (rewriter.get()) { if (rewriter.get()) {
// rewriter->trap(); // rewriter->trap();
GetattrRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0), rewriter->getReturnDestination()); GetattrRewriteArgs rewrite_args(rewriter.get(), rewriter->getArg(0), rewriter->getReturnDestination());
gotten = getclsattr_internal(obj, attr, &rewrite_args); gotten = getclsattrInternal(obj, attr, &rewrite_args);
if (rewrite_args.out_success && gotten) { if (rewrite_args.out_success && gotten) {
rewriter->commitReturning(rewrite_args.out_rtn); rewriter->commitReturning(rewrite_args.out_rtn);
...@@ -1142,7 +1171,7 @@ extern "C" Box* getclsattr(Box* obj, const char* attr) { ...@@ -1142,7 +1171,7 @@ extern "C" Box* getclsattr(Box* obj, const char* attr) {
#endif #endif
} }
else { else {
gotten = getclsattr_internal(obj, attr, NULL); gotten = getclsattrInternal(obj, attr, NULL);
} }
RELEASE_ASSERT(gotten, "%s:%s", getTypeName(obj), attr); RELEASE_ASSERT(gotten, "%s:%s", getTypeName(obj), attr);
...@@ -1173,12 +1202,13 @@ static Box* (*runtimeCall2)(Box*, ArgPassSpec, Box*, Box*) = (Box * (*)(Box*, Ar ...@@ -1173,12 +1202,13 @@ static Box* (*runtimeCall2)(Box*, ArgPassSpec, Box*, Box*) = (Box * (*)(Box*, Ar
static Box* (*runtimeCall3)(Box*, ArgPassSpec, Box*, Box*, Box*) static Box* (*runtimeCall3)(Box*, ArgPassSpec, Box*, Box*, Box*)
= (Box * (*)(Box*, ArgPassSpec, Box*, Box*, Box*))runtimeCall; = (Box * (*)(Box*, ArgPassSpec, Box*, Box*, Box*))runtimeCall;
Box* getattrInternalGeneral(Box* obj, const std::string& attr, GetattrRewriteArgs* rewrite_args, bool cls_only, Box* getattrInternalGeneric(Box* obj, const std::string& attr, GetattrRewriteArgs* rewrite_args, bool cls_only,
bool for_call, Box** bind_obj_out, RewriterVar** r_bind_obj_out) { bool for_call, Box** bind_obj_out, RewriterVar** r_bind_obj_out) {
if (for_call) { if (for_call) {
*bind_obj_out = NULL; *bind_obj_out = NULL;
} }
// TODO this should be a custom getattr
if (obj->cls == closure_cls) { if (obj->cls == closure_cls) {
Box* val = NULL; Box* val = NULL;
if (rewrite_args) { if (rewrite_args) {
...@@ -1213,23 +1243,6 @@ Box* getattrInternalGeneral(Box* obj, const std::string& attr, GetattrRewriteArg ...@@ -1213,23 +1243,6 @@ Box* getattrInternalGeneral(Box* obj, const std::string& attr, GetattrRewriteArg
raiseExcHelper(NameError, "free variable '%s' referenced before assignment in enclosing scope", attr.c_str()); raiseExcHelper(NameError, "free variable '%s' referenced before assignment in enclosing scope", attr.c_str());
} }
if (!cls_only) {
// Don't need to pass icentry args, since we special-case __getattribtue__ and __getattr__ to use
// invalidation rather than guards
// TODO since you changed this to typeLookup you need to guard
Box* getattribute = typeLookup(obj->cls, getattribute_str, NULL);
if (getattribute) {
// TODO this is a good candidate for interning?
Box* boxstr = boxString(attr);
Box* rtn = runtimeCall2(getattribute, ArgPassSpec(2), obj, boxstr);
return rtn;
}
if (rewrite_args) {
rewrite_args->rewriter->addDependenceOn(obj->cls->dependent_icgetattrs);
}
}
// Handle descriptor logic here. // Handle descriptor logic here.
// A descriptor is either a data descriptor or a non-data descriptor. // A descriptor is either a data descriptor or a non-data descriptor.
// data descriptors define both __get__ and __set__. non-data descriptors // data descriptors define both __get__ and __set__. non-data descriptors
...@@ -1499,35 +1512,11 @@ Box* getattrInternalGeneral(Box* obj, const std::string& attr, GetattrRewriteArg ...@@ -1499,35 +1512,11 @@ Box* getattrInternalGeneral(Box* obj, const std::string& attr, GetattrRewriteArg
// TODO this shouldn't go here; it should be in instancemethod_cls->tp_getattr[o] // TODO this shouldn't go here; it should be in instancemethod_cls->tp_getattr[o]
if (obj->cls == instancemethod_cls) { if (obj->cls == instancemethod_cls) {
assert(!rewrite_args || !rewrite_args->out_success); assert(!rewrite_args || !rewrite_args->out_success);
return getattrInternalGeneral(static_cast<BoxedInstanceMethod*>(obj)->func, attr, NULL, cls_only, for_call, return getattrInternalEx(static_cast<BoxedInstanceMethod*>(obj)->func, attr, NULL, cls_only, for_call,
bind_obj_out, NULL); bind_obj_out, NULL);
} }
// Finally, check __getattr__ // Finally, check __getattr__
if (!cls_only) {
// Don't need to pass icentry args, since we special-case __getattribute__ and __getattr__ to use
// invalidation rather than guards
rewrite_args = NULL;
REWRITE_ABORTED("");
if (obj->cls->tp_getattr) {
Box* rtn = obj->cls->tp_getattr(obj, const_cast<char*>(attr.c_str()));
if (rtn == NULL)
throwCAPIException();
return rtn;
}
Box* getattr = typeLookup(obj->cls, getattr_str, NULL);
if (getattr) {
Box* boxstr = boxString(attr);
Box* rtn = runtimeCall2(getattr, ArgPassSpec(2), obj, boxstr);
return rtn;
}
if (rewrite_args) {
rewrite_args->rewriter->addDependenceOn(obj->cls->dependent_icgetattrs);
}
}
if (rewrite_args) { if (rewrite_args) {
rewrite_args->out_success = true; rewrite_args->out_success = true;
} }
...@@ -1535,7 +1524,7 @@ Box* getattrInternalGeneral(Box* obj, const std::string& attr, GetattrRewriteArg ...@@ -1535,7 +1524,7 @@ Box* getattrInternalGeneral(Box* obj, const std::string& attr, GetattrRewriteArg
} }
Box* getattrInternal(Box* obj, const std::string& attr, GetattrRewriteArgs* rewrite_args) { Box* getattrInternal(Box* obj, const std::string& attr, GetattrRewriteArgs* rewrite_args) {
return getattrInternalGeneral(obj, attr, rewrite_args, return getattrInternalEx(obj, attr, rewrite_args,
/* cls_only */ false, /* cls_only */ false,
/* for_call */ false, NULL, NULL); /* for_call */ false, NULL, NULL);
} }
...@@ -1878,9 +1867,9 @@ extern "C" bool nonzero(Box* obj) { ...@@ -1878,9 +1867,9 @@ extern "C" bool nonzero(Box* obj) {
// Stats::log(id); // Stats::log(id);
// go through descriptor logic // go through descriptor logic
Box* func = getclsattr_internal(obj, "__nonzero__", NULL); Box* func = getclsattrInternal(obj, "__nonzero__", NULL);
if (!func) if (!func)
func = getclsattr_internal(obj, "__len__", NULL); func = getclsattrInternal(obj, "__len__", NULL);
if (func == NULL) { if (func == NULL) {
ASSERT(isUserDefined(obj->cls) || obj->cls == classobj_cls || obj->cls == type_cls ASSERT(isUserDefined(obj->cls) || obj->cls == classobj_cls || obj->cls == type_cls
...@@ -2001,7 +1990,7 @@ extern "C" BoxedInt* hash(Box* obj) { ...@@ -2001,7 +1990,7 @@ extern "C" BoxedInt* hash(Box* obj) {
slowpath_hash.log(); slowpath_hash.log();
// goes through descriptor logic // goes through descriptor logic
Box* hash = getclsattr_internal(obj, "__hash__", NULL); Box* hash = getclsattrInternal(obj, "__hash__", NULL);
if (hash == NULL) { if (hash == NULL) {
ASSERT(isUserDefined(obj->cls) || obj->cls == function_cls || obj->cls == object_cls || obj->cls == classobj_cls ASSERT(isUserDefined(obj->cls) || obj->cls == function_cls || obj->cls == object_cls || obj->cls == classobj_cls
...@@ -2241,20 +2230,20 @@ extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope ...@@ -2241,20 +2230,20 @@ extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope
// Look up the argument. Pass in the arguments to getattrInternalGeneral or getclsattr_general // Look up the argument. Pass in the arguments to getattrInternalGeneral or getclsattr_general
// that will shortcut functions by not putting them into instancemethods // that will shortcut functions by not putting them into instancemethods
Box* bind_obj; Box* bind_obj = NULL; // Initialize this to NULL to allow getattrInternalEx to ignore it
RewriterVar* r_bind_obj; RewriterVar* r_bind_obj;
Box* val; Box* val;
RewriterVar* r_val = NULL; RewriterVar* r_val = NULL;
if (rewrite_args) { if (rewrite_args) {
GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, rewrite_args->obj, Location::any()); GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, rewrite_args->obj, Location::any());
val = getattrInternalGeneral(obj, *attr, &grewrite_args, scope == CLASS_ONLY, true, &bind_obj, &r_bind_obj); val = getattrInternalEx(obj, *attr, &grewrite_args, scope == CLASS_ONLY, true, &bind_obj, &r_bind_obj);
if (!grewrite_args.out_success) { if (!grewrite_args.out_success) {
rewrite_args = NULL; rewrite_args = NULL;
} else if (val) { } else if (val) {
r_val = grewrite_args.out_rtn; r_val = grewrite_args.out_rtn;
} }
} else { } else {
val = getattrInternalGeneral(obj, *attr, NULL, scope == CLASS_ONLY, true, &bind_obj, &r_bind_obj); val = getattrInternalEx(obj, *attr, NULL, scope == CLASS_ONLY, true, &bind_obj, &r_bind_obj);
} }
if (val == NULL) { if (val == NULL) {
...@@ -2343,14 +2332,6 @@ extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope ...@@ -2343,14 +2332,6 @@ extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope
} }
} else { } else {
Box* rtn; Box* rtn;
// I *think* this check is here to limit the recursion nesting for rewriting, and originates
// from a time when we didn't have silent-abort-when-patchpoint-full.
if (val->cls != function_cls && val->cls != builtin_function_or_method_cls && val->cls != instancemethod_cls
&& val->cls != capifunc_cls) {
rewrite_args = NULL;
REWRITE_ABORTED("");
}
if (rewrite_args) { if (rewrite_args) {
CallRewriteArgs srewrite_args(rewrite_args->rewriter, r_val, rewrite_args->destination); CallRewriteArgs srewrite_args(rewrite_args->rewriter, r_val, rewrite_args->destination);
if (npassed_args >= 1) if (npassed_args >= 1)
...@@ -3456,7 +3437,7 @@ extern "C" Box* unaryop(Box* operand, int op_type) { ...@@ -3456,7 +3437,7 @@ extern "C" Box* unaryop(Box* operand, int op_type) {
const std::string& op_name = getOpName(op_type); const std::string& op_name = getOpName(op_type);
Box* attr_func = getclsattr_internal(operand, op_name, NULL); Box* attr_func = getclsattrInternal(operand, op_name, NULL);
ASSERT(attr_func, "%s.%s", getTypeName(operand), op_name.c_str()); ASSERT(attr_func, "%s.%s", getTypeName(operand), op_name.c_str());
......
...@@ -121,7 +121,7 @@ extern "C" void delattr_internal(Box* obj, const std::string& attr, bool allow_c ...@@ -121,7 +121,7 @@ extern "C" void delattr_internal(Box* obj, const std::string& attr, bool allow_c
struct CompareRewriteArgs; struct CompareRewriteArgs;
Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs* rewrite_args); Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs* rewrite_args);
Box* getattrInternal(Box* obj, const std::string& attr, GetattrRewriteArgs* rewrite_args); Box* getattrInternal(Box* obj, const std::string& attr, GetattrRewriteArgs* rewrite_args);
Box* getattrInternalGeneral(Box* obj, const std::string& attr, GetattrRewriteArgs* rewrite_args, bool cls_only, Box* getattrInternalGeneric(Box* obj, const std::string& attr, GetattrRewriteArgs* rewrite_args, bool cls_only,
bool for_call, Box** bind_obj_out, RewriterVar** r_bind_obj_out); bool for_call, Box** bind_obj_out, RewriterVar** r_bind_obj_out);
Box* typeLookup(BoxedClass* cls, const std::string& attr, GetattrRewriteArgs* rewrite_args); Box* typeLookup(BoxedClass* cls, const std::string& attr, GetattrRewriteArgs* rewrite_args);
......
...@@ -144,7 +144,11 @@ extern "C" void abort() { ...@@ -144,7 +144,11 @@ extern "C" void abort() {
// that object, _printStackTrace will hang waiting for the first construction // that object, _printStackTrace will hang waiting for the first construction
// to finish.) // to finish.)
alarm(1); alarm(1);
try {
_printStacktrace(); _printStacktrace();
} catch (ExcInfo) {
fprintf(stderr, "error printing stack trace during abort()");
}
// Cancel the alarm. // Cancel the alarm.
// This is helpful for when running in a debugger, since the debugger will catch the // This is helpful for when running in a debugger, since the debugger will catch the
......
...@@ -104,7 +104,8 @@ extern "C" PyObject* PystonType_GenericAlloc(BoxedClass* cls, Py_ssize_t nitems) ...@@ -104,7 +104,8 @@ extern "C" PyObject* PystonType_GenericAlloc(BoxedClass* cls, Py_ssize_t nitems)
} }
#endif #endif
if (!cls->tp_mro) { if (!cls->tp_mro) {
assert(!attrwrapper_cls); // the last class to be set up during bootstrapping // wrapperdescr_cls is the last class to be set up during bootstrapping:
ASSERT(!wrapperdescr_cls, "looks like we need to set up the mro for %s manually", cls->tp_name);
} else { } else {
assert(cls->tp_mro && "maybe we should just skip these checks if !mro"); assert(cls->tp_mro && "maybe we should just skip these checks if !mro");
assert(cls->tp_mro->cls == tuple_cls); assert(cls->tp_mro->cls == tuple_cls);
...@@ -432,6 +433,8 @@ extern "C" void typeGCHandler(GCVisitor* v, Box* b) { ...@@ -432,6 +433,8 @@ extern "C" void typeGCHandler(GCVisitor* v, Box* b) {
v->visit(cls->tp_mro); v->visit(cls->tp_mro);
if (cls->tp_bases) if (cls->tp_bases)
v->visit(cls->tp_bases); v->visit(cls->tp_bases);
if (cls->tp_subclasses)
v->visit(cls->tp_subclasses);
if (cls->tp_flags & Py_TPFLAGS_HEAPTYPE) { if (cls->tp_flags & Py_TPFLAGS_HEAPTYPE) {
BoxedHeapClass* hcls = static_cast<BoxedHeapClass*>(cls); BoxedHeapClass* hcls = static_cast<BoxedHeapClass*>(cls);
...@@ -1735,6 +1738,36 @@ void setupRuntime() { ...@@ -1735,6 +1738,36 @@ void setupRuntime() {
= new BoxedHeapClass(object_cls, NULL, 0, 0, sizeof(BoxedGetsetDescriptor), false, boxStrConstant("getset")); = new BoxedHeapClass(object_cls, NULL, 0, 0, sizeof(BoxedGetsetDescriptor), false, boxStrConstant("getset"));
attrwrapper_cls = new BoxedHeapClass(object_cls, &AttrWrapper::gcHandler, 0, 0, sizeof(AttrWrapper), false, attrwrapper_cls = new BoxedHeapClass(object_cls, &AttrWrapper::gcHandler, 0, 0, sizeof(AttrWrapper), false,
new BoxedString("attrwrapper")); new BoxedString("attrwrapper"));
dict_cls = new BoxedHeapClass(object_cls, &dictGCHandler, 0, 0, sizeof(BoxedDict), false, new BoxedString("dict"));
file_cls = new BoxedHeapClass(object_cls, NULL, 0, offsetof(BoxedFile, weakreflist), sizeof(BoxedFile), false,
new BoxedString("file"));
int_cls = new BoxedHeapClass(object_cls, NULL, 0, 0, sizeof(BoxedInt), false, new BoxedString("int"));
bool_cls = new BoxedHeapClass(int_cls, NULL, 0, 0, sizeof(BoxedBool), false, new BoxedString("bool"));
complex_cls = new BoxedHeapClass(object_cls, NULL, 0, 0, sizeof(BoxedComplex), false, new BoxedString("complex"));
long_cls = new BoxedHeapClass(object_cls, &BoxedLong::gchandler, 0, 0, sizeof(BoxedLong), false,
new BoxedString("long"));
float_cls = new BoxedHeapClass(object_cls, NULL, 0, 0, sizeof(BoxedFloat), false, new BoxedString("float"));
function_cls = new BoxedHeapClass(object_cls, &functionGCHandler, offsetof(BoxedFunction, attrs),
offsetof(BoxedFunction, in_weakreflist), sizeof(BoxedFunction), false,
new BoxedString("function"));
builtin_function_or_method_cls = new BoxedHeapClass(
object_cls, &functionGCHandler, 0, offsetof(BoxedBuiltinFunctionOrMethod, in_weakreflist),
sizeof(BoxedBuiltinFunctionOrMethod), false, new BoxedString("builtin_function_or_method"));
function_cls->simple_destructor = builtin_function_or_method_cls->simple_destructor = functionDtor;
module_cls = new BoxedHeapClass(object_cls, NULL, offsetof(BoxedModule, attrs), 0, sizeof(BoxedModule), false,
new BoxedString("module"));
member_cls
= new BoxedHeapClass(object_cls, NULL, 0, 0, sizeof(BoxedMemberDescriptor), false, new BoxedString("member"));
capifunc_cls
= new BoxedHeapClass(object_cls, NULL, 0, 0, sizeof(BoxedCApiFunction), false, new BoxedString("capifunc"));
method_cls
= new BoxedHeapClass(object_cls, NULL, 0, 0, sizeof(BoxedMethodDescriptor), false, new BoxedString("method"));
wrapperobject_cls = new BoxedHeapClass(object_cls, NULL, 0, 0, sizeof(BoxedWrapperObject), false,
new BoxedString("method-wrapper"));
wrapperdescr_cls = new BoxedHeapClass(object_cls, NULL, 0, 0, sizeof(BoxedWrapperDescriptor), false,
new BoxedString("wrapper_descriptor"));
// Kind of hacky, but it's easier to manually construct the mro for a couple key classes // Kind of hacky, but it's easier to manually construct the mro for a couple key classes
...@@ -1746,6 +1779,47 @@ void setupRuntime() { ...@@ -1746,6 +1779,47 @@ void setupRuntime() {
type_cls->tp_mro = new BoxedTuple({ type_cls, object_cls }); type_cls->tp_mro = new BoxedTuple({ type_cls, object_cls });
pyston_getset_cls->tp_mro = new BoxedTuple({ pyston_getset_cls, object_cls }); pyston_getset_cls->tp_mro = new BoxedTuple({ pyston_getset_cls, object_cls });
attrwrapper_cls->tp_mro = new BoxedTuple({ attrwrapper_cls, object_cls }); attrwrapper_cls->tp_mro = new BoxedTuple({ attrwrapper_cls, object_cls });
dict_cls->tp_mro = new BoxedTuple({ dict_cls, object_cls });
file_cls->tp_mro = new BoxedTuple({ file_cls, object_cls });
int_cls->tp_mro = new BoxedTuple({ int_cls, object_cls });
bool_cls->tp_mro = new BoxedTuple({ bool_cls, object_cls });
complex_cls->tp_mro = new BoxedTuple({ complex_cls, object_cls });
long_cls->tp_mro = new BoxedTuple({ long_cls, object_cls });
float_cls->tp_mro = new BoxedTuple({ float_cls, object_cls });
function_cls->tp_mro = new BoxedTuple({ function_cls, object_cls });
builtin_function_or_method_cls->tp_mro = new BoxedTuple({ builtin_function_or_method_cls, object_cls });
member_cls->tp_mro = new BoxedTuple({ member_cls, object_cls });
capifunc_cls->tp_mro = new BoxedTuple({ capifunc_cls, object_cls });
module_cls->tp_mro = new BoxedTuple({ module_cls, object_cls });
method_cls->tp_mro = new BoxedTuple({ method_cls, object_cls });
wrapperobject_cls->tp_mro = new BoxedTuple({ wrapperobject_cls, object_cls });
wrapperdescr_cls->tp_mro = new BoxedTuple({ wrapperdescr_cls, object_cls });
STR = typeFromClass(str_cls);
BOXED_INT = typeFromClass(int_cls);
BOXED_FLOAT = typeFromClass(float_cls);
BOXED_BOOL = typeFromClass(bool_cls);
NONE = typeFromClass(none_cls);
LIST = typeFromClass(list_cls);
MODULE = typeFromClass(module_cls);
DICT = typeFromClass(dict_cls);
BOXED_TUPLE = typeFromClass(tuple_cls);
LONG = typeFromClass(long_cls);
BOXED_COMPLEX = typeFromClass(complex_cls);
True = new BoxedBool(true);
False = new BoxedBool(false);
gc::registerPermanentRoot(True);
gc::registerPermanentRoot(False);
// Need to initialize interned_ints early:
setupInt();
// sys is the first module that needs to be set up, due to modules
// being tracked in sys.modules:
setupSys();
// Weakrefs are used for tp_subclasses:
init_weakref();
object_cls->finishInitialization(); object_cls->finishInitialization();
type_cls->finishInitialization(); type_cls->finishInitialization();
...@@ -1756,6 +1830,24 @@ void setupRuntime() { ...@@ -1756,6 +1830,24 @@ void setupRuntime() {
list_cls->finishInitialization(); list_cls->finishInitialization();
pyston_getset_cls->finishInitialization(); pyston_getset_cls->finishInitialization();
attrwrapper_cls->finishInitialization(); attrwrapper_cls->finishInitialization();
dict_cls->finishInitialization();
file_cls->finishInitialization();
int_cls->finishInitialization();
bool_cls->finishInitialization();
complex_cls->finishInitialization();
long_cls->finishInitialization();
float_cls->finishInitialization();
function_cls->finishInitialization();
builtin_function_or_method_cls->finishInitialization();
member_cls->finishInitialization();
module_cls->finishInitialization();
capifunc_cls->finishInitialization();
method_cls->finishInitialization();
wrapperobject_cls->finishInitialization();
wrapperdescr_cls->finishInitialization();
object_cls->tp_getattro = PyObject_GenericGetAttr;
add_operators(object_cls);
str_cls->tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER; str_cls->tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER;
...@@ -1764,42 +1856,15 @@ void setupRuntime() { ...@@ -1764,42 +1856,15 @@ void setupRuntime() {
type_cls->giveAttr("__dict__", dict_descr); type_cls->giveAttr("__dict__", dict_descr);
module_cls = BoxedHeapClass::create(type_cls, object_cls, NULL, offsetof(BoxedModule, attrs), 0,
sizeof(BoxedModule), false, "module");
// TODO it'd be nice to be able to do these in the respective setupType methods,
// but those setup methods probably want access to these objects.
// We could have a multi-stage setup process, but that seems overkill for now.
int_cls = BoxedHeapClass::create(type_cls, object_cls, NULL, 0, 0, sizeof(BoxedInt), false, "int");
bool_cls = BoxedHeapClass::create(type_cls, int_cls, NULL, 0, 0, sizeof(BoxedBool), false, "bool");
complex_cls = BoxedHeapClass::create(type_cls, object_cls, NULL, 0, 0, sizeof(BoxedComplex), false, "complex");
long_cls
= BoxedHeapClass::create(type_cls, object_cls, &BoxedLong::gchandler, 0, 0, sizeof(BoxedLong), false, "long");
float_cls = BoxedHeapClass::create(type_cls, object_cls, NULL, 0, 0, sizeof(BoxedFloat), false, "float");
function_cls
= BoxedHeapClass::create(type_cls, object_cls, &functionGCHandler, offsetof(BoxedFunction, attrs),
offsetof(BoxedFunction, in_weakreflist), sizeof(BoxedFunction), false, "function");
builtin_function_or_method_cls = BoxedHeapClass::create(
type_cls, object_cls, &functionGCHandler, 0, offsetof(BoxedBuiltinFunctionOrMethod, in_weakreflist),
sizeof(BoxedBuiltinFunctionOrMethod), false, "builtin_function_or_method");
function_cls->simple_destructor = builtin_function_or_method_cls->simple_destructor = functionDtor;
instancemethod_cls = BoxedHeapClass::create(type_cls, object_cls, &instancemethodGCHandler, 0, instancemethod_cls = BoxedHeapClass::create(type_cls, object_cls, &instancemethodGCHandler, 0,
offsetof(BoxedInstanceMethod, in_weakreflist), offsetof(BoxedInstanceMethod, in_weakreflist),
sizeof(BoxedInstanceMethod), false, "instancemethod"); sizeof(BoxedInstanceMethod), false, "instancemethod");
list_cls = BoxedHeapClass::create(type_cls, object_cls, &listGCHandler, 0, 0, sizeof(BoxedList), false, "list");
slice_cls = BoxedHeapClass::create(type_cls, object_cls, &sliceGCHandler, 0, 0, sizeof(BoxedSlice), false, "slice"); slice_cls = BoxedHeapClass::create(type_cls, object_cls, &sliceGCHandler, 0, 0, sizeof(BoxedSlice), false, "slice");
dict_cls = BoxedHeapClass::create(type_cls, object_cls, &dictGCHandler, 0, 0, sizeof(BoxedDict), false, "dict");
file_cls = BoxedHeapClass::create(type_cls, object_cls, NULL, 0, offsetof(BoxedFile, weakreflist),
sizeof(BoxedFile), false, "file");
set_cls = BoxedHeapClass::create(type_cls, object_cls, &setGCHandler, 0, offsetof(BoxedSet, weakreflist), set_cls = BoxedHeapClass::create(type_cls, object_cls, &setGCHandler, 0, offsetof(BoxedSet, weakreflist),
sizeof(BoxedSet), false, "set"); sizeof(BoxedSet), false, "set");
frozenset_cls = BoxedHeapClass::create(type_cls, object_cls, &setGCHandler, 0, offsetof(BoxedSet, weakreflist), frozenset_cls = BoxedHeapClass::create(type_cls, object_cls, &setGCHandler, 0, offsetof(BoxedSet, weakreflist),
sizeof(BoxedSet), false, "frozenset"); sizeof(BoxedSet), false, "frozenset");
member_cls
= BoxedHeapClass::create(type_cls, object_cls, NULL, 0, 0, sizeof(BoxedMemberDescriptor), false, "member");
capi_getset_cls capi_getset_cls
= BoxedHeapClass::create(type_cls, object_cls, NULL, 0, 0, sizeof(BoxedGetsetDescriptor), false, "getset"); = BoxedHeapClass::create(type_cls, object_cls, NULL, 0, 0, sizeof(BoxedGetsetDescriptor), false, "getset");
closure_cls = BoxedHeapClass::create(type_cls, object_cls, &closureGCHandler, offsetof(BoxedClosure, attrs), 0, closure_cls = BoxedHeapClass::create(type_cls, object_cls, &closureGCHandler, offsetof(BoxedClosure, attrs), 0,
...@@ -1817,20 +1882,9 @@ void setupRuntime() { ...@@ -1817,20 +1882,9 @@ void setupRuntime() {
pyston_getset_cls->freeze(); pyston_getset_cls->freeze();
capi_getset_cls->freeze(); capi_getset_cls->freeze();
STR = typeFromClass(str_cls);
BOXED_INT = typeFromClass(int_cls);
BOXED_FLOAT = typeFromClass(float_cls);
BOXED_BOOL = typeFromClass(bool_cls);
NONE = typeFromClass(none_cls);
LIST = typeFromClass(list_cls);
SLICE = typeFromClass(slice_cls); SLICE = typeFromClass(slice_cls);
MODULE = typeFromClass(module_cls);
DICT = typeFromClass(dict_cls);
SET = typeFromClass(set_cls); SET = typeFromClass(set_cls);
FROZENSET = typeFromClass(frozenset_cls); FROZENSET = typeFromClass(frozenset_cls);
BOXED_TUPLE = typeFromClass(tuple_cls);
LONG = typeFromClass(long_cls);
BOXED_COMPLEX = typeFromClass(complex_cls);
object_cls->giveAttr("__new__", new BoxedFunction(boxRTFunction((void*)objectNew, UNKNOWN, 1, 0, true, true))); object_cls->giveAttr("__new__", new BoxedFunction(boxRTFunction((void*)objectNew, UNKNOWN, 1, 0, true, true)));
object_cls->giveAttr("__init__", new BoxedFunction(boxRTFunction((void*)objectInit, UNKNOWN, 1, 0, true, false))); object_cls->giveAttr("__init__", new BoxedFunction(boxRTFunction((void*)objectInit, UNKNOWN, 1, 0, true, false)));
...@@ -1878,7 +1932,6 @@ void setupRuntime() { ...@@ -1878,7 +1932,6 @@ void setupRuntime() {
object_cls->freeze(); object_cls->freeze();
setupBool(); setupBool();
setupInt();
setupLong(); setupLong();
setupFloat(); setupFloat();
setupComplex(); setupComplex();
...@@ -1970,10 +2023,6 @@ void setupRuntime() { ...@@ -1970,10 +2023,6 @@ void setupRuntime() {
attrwrapperiter_cls->giveAttr("next", new BoxedFunction(boxRTFunction((void*)AttrWrapperIter::next, UNKNOWN, 1))); attrwrapperiter_cls->giveAttr("next", new BoxedFunction(boxRTFunction((void*)AttrWrapperIter::next, UNKNOWN, 1)));
attrwrapperiter_cls->freeze(); attrwrapperiter_cls->freeze();
// sys is the first module that needs to be set up, due to modules
// being tracked in sys.modules:
setupSys();
setupBuiltins(); setupBuiltins();
_PyExc_Init(); _PyExc_Init();
setupThread(); setupThread();
...@@ -2012,7 +2061,6 @@ void setupRuntime() { ...@@ -2012,7 +2061,6 @@ void setupRuntime() {
init_codecs(); init_codecs();
init_socket(); init_socket();
initunicodedata(); initunicodedata();
init_weakref();
initcStringIO(); initcStringIO();
init_io(); init_io();
initzipimport(); initzipimport();
......
...@@ -204,6 +204,7 @@ protected: ...@@ -204,6 +204,7 @@ protected:
bool is_user_defined); bool is_user_defined);
friend void setupRuntime(); friend void setupRuntime();
friend void setupSysEnd();
}; };
class BoxedHeapClass : public BoxedClass { class BoxedHeapClass : public BoxedClass {
...@@ -232,6 +233,7 @@ private: ...@@ -232,6 +233,7 @@ private:
bool is_user_defined, BoxedString* name); bool is_user_defined, BoxedString* name);
friend void setupRuntime(); friend void setupRuntime();
friend void setupSys();
DEFAULT_CLASS(type_cls); DEFAULT_CLASS(type_cls);
}; };
......
# expected: fail
# - object.__getattribute__ doesn't exist
# attr-getting resolution. # attr-getting resolution.
class M(type): class M(type):
......
...@@ -53,8 +53,6 @@ else: ...@@ -53,8 +53,6 @@ else:
print 'False' print 'False'
# __getattr__ and __setattr__ # __getattr__ and __setattr__
# Looks like __getattr__ and __setattr__ should *not* be looked up with
# the descriptor protocol
class DescriptorGetattr(object): class DescriptorGetattr(object):
def __get__(self, obj, type): def __get__(self, obj, type):
print 'getattr __get__ called' print 'getattr __get__ called'
...@@ -68,8 +66,8 @@ class DescriptorSetattr(object): ...@@ -68,8 +66,8 @@ class DescriptorSetattr(object):
def setattr(attr, val): def setattr(attr, val):
print 'setattr called for attr', attr, val print 'setattr called for attr', attr, val
class D(object): class D(object):
__getattr__ = DescriptorGetattr __getattr__ = DescriptorGetattr()
__setattr__ = DescriptorSetattr __setattr__ = DescriptorSetattr()
d = D() d = D()
try: try:
......
...@@ -6,8 +6,15 @@ class C(object): ...@@ -6,8 +6,15 @@ class C(object):
else: else:
object.__setattr__(self, attr, value) object.__setattr__(self, attr, value)
def __getattribute__(self, attr):
print "getattribute", attr
if attr.startswith("c"):
return "yum"
return object.__getattribute__(self, attr)
c = C() c = C()
c.a = 1 c.a = 1
c.b = 2 c.b = 2
c.c = 3 c.c = 3
print sorted(c.__dict__.items()) print sorted(c.__dict__.items())
print c.a, c.b, c.c
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