Commit 2489e96f authored by Travis Hance's avatar Travis Hance

kmod's comments on slots

parent 6469984e
......@@ -440,7 +440,6 @@ public:
// Add a no-op constructor to make sure that we don't zero-initialize cls
Box() {}
void* operator new(size_t size, BoxedClass* cls, size_t nitems) __attribute__((visibility("default")));
void* operator new(size_t size, BoxedClass* cls) __attribute__((visibility("default")));
void operator delete(void* ptr) __attribute__((visibility("default"))) { abort(); }
......@@ -485,11 +484,11 @@ extern "C" PyObject* PystonType_GenericAlloc(BoxedClass* cls, Py_ssize_t nitems)
#define DEFAULT_CLASS(default_cls) \
void* operator new(size_t size, BoxedClass * cls) __attribute__((visibility("default"))) { \
assert(cls->tp_itemsize == 0); \
return Box::operator new(size, cls, 0); \
return Box::operator new(size, cls); \
} \
void* operator new(size_t size) __attribute__((visibility("default"))) { \
assert(default_cls->tp_itemsize == 0); \
return Box::operator new(size, default_cls, 0); \
return Box::operator new(size, default_cls); \
}
// The restrictions on when you can use the SIMPLE (ie fast) variant are encoded as
......@@ -531,11 +530,11 @@ extern "C" PyObject* PystonType_GenericAlloc(BoxedClass* cls, Py_ssize_t nitems)
\
void* operator new(size_t size, BoxedClass * cls, size_t nitems) __attribute__((visibility("default"))) { \
assert(cls->tp_itemsize == itemsize); \
return Box::operator new(size, cls, nitems); \
return BoxVar::operator new(size, cls, nitems); \
} \
void* operator new(size_t size, size_t nitems) __attribute__((visibility("default"))) { \
assert(default_cls->tp_itemsize == itemsize); \
return Box::operator new(size, default_cls, nitems); \
return BoxVar::operator new(size, default_cls, nitems); \
}
#define DEFAULT_CLASS_VAR_SIMPLE(default_cls, itemsize) \
......@@ -546,7 +545,7 @@ extern "C" PyObject* PystonType_GenericAlloc(BoxedClass* cls, Py_ssize_t nitems)
\
void* operator new(size_t size, BoxedClass * cls, size_t nitems) __attribute__((visibility("default"))) { \
assert(cls->tp_itemsize == itemsize); \
return Box::operator new(size, cls, nitems); \
return BoxVar::operator new(size, cls, nitems); \
} \
void* operator new(size_t size, size_t nitems) __attribute__((visibility("default"))) { \
assert(default_cls->tp_alloc == PystonType_GenericAlloc); \
......@@ -571,6 +570,8 @@ public:
BoxVar() {}
BoxVar(Py_ssize_t ob_size) : ob_size(ob_size) {}
void* operator new(size_t size, BoxedClass* cls, size_t nitems) __attribute__((visibility("default")));
};
static_assert(offsetof(BoxVar, ob_size) == offsetof(struct _varobject, ob_size), "");
......
......@@ -3977,30 +3977,6 @@ static void assertInitNone(Box* obj) {
}
}
// Modified from `valid_identifier` in CPython typeobject.c
static int valid_identifier(PyObject* s) {
unsigned char* p;
Py_ssize_t i, n;
if (!PyString_Check(s)) {
PyErr_Format(PyExc_TypeError, "__slots__ items must be strings, not '%.200s'", Py_TYPE(s)->tp_name);
return 0;
}
p = (unsigned char*)PyString_AS_STRING(s);
n = PyString_GET_SIZE(s);
/* We must reject an empty name. As a hack, we bump the
length to 1 so that the loop will balk on the trailing \0. */
if (n == 0)
n = 1;
for (i = 0; i < n; i++, p++) {
if (!(i == 0 ? isalpha(*p) : isalnum(*p)) && *p != '_') {
PyErr_SetString(PyExc_TypeError, "__slots__ must be identifiers");
return 0;
}
}
return 1;
}
void assertValidSlotIdentifier(Box* s) {
// Ported from `valid_identifier` in cpython
......
......@@ -178,9 +178,10 @@ extern "C" PyObject* _PyObject_New(PyTypeObject* tp) noexcept {
}
// Analogue of PyType_GenericNew
void* Box::operator new(size_t size, BoxedClass* cls, size_t nitems) {
void* BoxVar::operator new(size_t size, BoxedClass* cls, size_t nitems) {
assert(cls);
ASSERT(cls->tp_basicsize >= size, "%s", cls->tp_name);
assert(cls->tp_itemsize > 0);
assert(cls->tp_alloc);
void* mem = cls->tp_alloc(cls, nitems);
......@@ -189,7 +190,14 @@ void* Box::operator new(size_t size, BoxedClass* cls, size_t nitems) {
}
void* Box::operator new(size_t size, BoxedClass* cls) {
return Box::operator new(size, cls, 0);
assert(cls);
ASSERT(cls->tp_basicsize >= size, "%s", cls->tp_name);
assert(cls->tp_itemsize == 0);
assert(cls->tp_alloc);
void* mem = cls->tp_alloc(cls, 0);
RELEASE_ASSERT(mem, "");
return mem;
}
Box* BoxedClass::callHasnextIC(Box* obj, bool null_on_nonexistent) {
......
......@@ -66,3 +66,41 @@ try:
pass
except TypeError as e:
print e.message
print 'testing a lot of slots'
class C(object):
__slots__ = ['a' + str(i) for i in xrange(1000)]
c = C()
c.a0 = -8
print c.a0
for i in xrange(1000):
setattr(c, 'a' + str(i), i)
for i in xrange(1000):
print getattr(c, 'a' + str(i))
print 'slots on a subclass of str'
try:
class C(str):
__slots__ = ['a']
except TypeError as e:
print e.message
print 'slots on a class with a metaclass'
class M(type):
def __new__(*args):
print "M.__new__", args[:3]
return type.__new__(*args)
def __call__(*args):
print "M.__call__", args[:3]
return type.__call__(*args)
class C(object):
__metaclass__ = M
__slots__ = ['a', 'b']
c = C()
c.a = 5
print c.a
c.b = 6
print c.b
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