Skip to content

Commit e6b3445

Browse files
fangerertimfel
authored andcommitted
Add __new__ and copy tp_new slot before filling dict
1 parent 7e82486 commit e6b3445

File tree

1 file changed

+60
-29
lines changed

1 file changed

+60
-29
lines changed

graalpython/com.oracle.graal.python.cext/src/typeobject.c

Lines changed: 60 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -178,34 +178,19 @@ void PyType_Modified(PyTypeObject* type) {
178178
static void inherit_special(PyTypeObject *type, PyTypeObject *base) {
179179

180180
/* Copying basicsize is connected to the GC flags */
181-
unsigned long flags = PyTypeObject_tp_flags(type);
182-
unsigned long base_flags = PyTypeObject_tp_flags(base);
181+
unsigned long flags = PyTypeObject_tp_flags(type);
182+
unsigned long base_flags = PyTypeObject_tp_flags(base);
183183
if (!(flags & Py_TPFLAGS_HAVE_GC) &&
184184
(base_flags & Py_TPFLAGS_HAVE_GC) &&
185185
(!PyTypeObject_tp_traverse(type) && !PyTypeObject_tp_clear(type))) {
186-
flags |= Py_TPFLAGS_HAVE_GC;
186+
187+
flags |= Py_TPFLAGS_HAVE_GC;
187188
if (PyTypeObject_tp_traverse(type) == NULL)
188189
set_PyTypeObject_tp_traverse(type, PyTypeObject_tp_traverse(base));
189190
if (PyTypeObject_tp_clear(type) == NULL)
190-
set_PyTypeObject_tp_clear(type, PyTypeObject_tp_clear(base));
191-
}
192-
{
193-
/* The condition below could use some explanation.
194-
It appears that tp_new is not inherited for static types
195-
whose base class is 'object'; this seems to be a precaution
196-
so that old extension types don't suddenly become
197-
callable (object.__new__ wouldn't insure the invariants
198-
that the extension type's own factory function ensures).
199-
Heap types, of course, are under our control, so they do
200-
inherit tp_new; static extension types that specify some
201-
other built-in type as the default also
202-
inherit object.__new__. */
203-
if (base != &PyBaseObject_Type ||
204-
(flags & Py_TPFLAGS_HEAPTYPE)) {
205-
if (PyTypeObject_tp_new(type) == NULL)
206-
set_PyTypeObject_tp_new(type, PyTypeObject_tp_new(base)) ;
207-
}
191+
set_PyTypeObject_tp_clear(type, PyTypeObject_tp_clear(base));
208192
}
193+
209194
/* Copy other non-function slots */
210195

211196
#undef COPYVAL
@@ -238,7 +223,7 @@ static void inherit_special(PyTypeObject *type, PyTypeObject *base) {
238223
flags |= _Py_TPFLAGS_MATCH_SELF;
239224

240225
if (flags != PyTypeObject_tp_flags(type)) {
241-
set_PyTypeObject_tp_flags(type, flags);
226+
set_PyTypeObject_tp_flags(type, flags);
242227
}
243228
}
244229

@@ -372,13 +357,55 @@ static void add_slot(PyTypeObject* cls, PyObject* type_dict, char* name, void* m
372357
}
373358
}
374359

375-
#define ADD_MEMBER(__javacls__, __tpdict__, __mname__, __mtype__, __moffset__, __mflags__, __mdoc__) \
360+
#define ADD_MEMBER(__javacls__, __tpdict__, __mname__, __mtype__, __moffset__, __mflags__, __mdoc__) \
376361
add_member((__javacls__), (__tpdict__), (__mname__), (__mtype__), (__moffset__), (__mflags__), (__mdoc__))
377362

378363

379-
#define ADD_GETSET(__javacls__, __tpdict__, __name__, __getter__, __setter__, __doc__, __closure__) \
364+
#define ADD_GETSET(__javacls__, __tpdict__, __name__, __getter__, __setter__, __doc__, __closure__) \
380365
add_getset((__javacls__), (__tpdict__), (__name__), (__getter__), (__setter__), (__doc__), (__closure__))
381366

367+
// Set tp_new and the "__new__" key in the type dictionary.
368+
// Use the Py_TPFLAGS_DISALLOW_INSTANTIATION flag.
369+
static int
370+
type_ready_set_new(PyTypeObject *type, PyObject *dict, PyTypeObject *base)
371+
{
372+
/* The condition below could use some explanation.
373+
374+
It appears that tp_new is not inherited for static types whose base
375+
class is 'object'; this seems to be a precaution so that old extension
376+
types don't suddenly become callable (object.__new__ wouldn't insure the
377+
invariants that the extension type's own factory function ensures).
378+
379+
Heap types, of course, are under our control, so they do inherit tp_new;
380+
static extension types that specify some other built-in type as the
381+
default also inherit object.__new__. */
382+
newfunc tp_new = PyTypeObject_tp_new(type);
383+
unsigned long tp_flags = PyTypeObject_tp_flags(type);
384+
if (tp_new == NULL
385+
&& base == &PyBaseObject_Type
386+
&& !(tp_flags & Py_TPFLAGS_HEAPTYPE))
387+
{
388+
set_PyTypeObject_tp_flags(type, tp_flags |= Py_TPFLAGS_DISALLOW_INSTANTIATION);
389+
}
390+
391+
if (!(type->tp_flags & Py_TPFLAGS_DISALLOW_INSTANTIATION)) {
392+
if (tp_new != NULL) {
393+
// If "__new__" key does not exists in the type dictionary,
394+
// set it to tp_new_wrapper().
395+
add_slot(type, dict, "__new__", tp_new, METH_KEYWORDS | METH_VARARGS, JWRAPPER_NEW, NULL);
396+
}
397+
else {
398+
// tp_new is NULL: inherit tp_new from base
399+
set_PyTypeObject_tp_new(type, PyTypeObject_tp_new(base)) ;
400+
}
401+
}
402+
else {
403+
// Py_TPFLAGS_DISALLOW_INSTANTIATION sets tp_new to NULL
404+
// not supported yet
405+
// set_PyTypeObject_tp_new(type, NULL) ;
406+
}
407+
return 0;
408+
}
382409

383410
int PyType_Ready(PyTypeObject* cls) {
384411
#define RETURN_ERROR(__type__) \
@@ -388,7 +415,7 @@ int PyType_Ready(PyTypeObject* cls) {
388415
return -1; \
389416
} while(0)
390417

391-
#define ADD_IF_MISSING(attr, def) if (!(attr)) { attr = def; }
418+
#define ADD_IF_MISSING(OBJ, SLOT, VAL) if (!(PyTypeObject_##SLOT(OBJ))) { set_PyTypeObject_##SLOT((OBJ), (VAL)); }
392419
#define ADD_SLOT_CONV(__name__, __meth__, __flags__, __signature__) add_slot(cls, dict, (__name__), (__meth__), (__flags__), (__signature__), NULL)
393420

394421
Py_ssize_t n;
@@ -507,9 +534,8 @@ int PyType_Ready(PyTypeObject* cls) {
507534
PyObject* mro = GraalPyTruffle_Compute_Mro(cls, truffleString(cls->tp_name));
508535
set_PyTypeObject_tp_mro(cls, mro);
509536

510-
/* set new and alloc */
511-
ADD_IF_MISSING(cls->tp_alloc, PyType_GenericAlloc);
512-
ADD_IF_MISSING(cls->tp_new, PyType_GenericNew);
537+
/* set new */
538+
type_ready_set_new(cls, dict, base);
513539

514540
/* fill dict */
515541
// add special methods defined directly on the type structs
@@ -550,7 +576,9 @@ int PyType_Ready(PyTypeObject* cls) {
550576
ADD_SLOT_CONV("__set__", cls->tp_descr_set, -3, JWRAPPER_DESCR_SET);
551577
ADD_SLOT_CONV("__init__", cls->tp_init, METH_KEYWORDS | METH_VARARGS, JWRAPPER_INITPROC);
552578
ADD_SLOT_CONV("__alloc__", cls->tp_alloc, -2, JWRAPPER_ALLOC);
553-
ADD_SLOT_CONV("__new__", cls->tp_new, METH_KEYWORDS | METH_VARARGS, JWRAPPER_NEW);
579+
/* Note: '__new__' was added here previously but we don't do it similar to CPython.
580+
They also skip it because the appropriate 'slotdef' doesn't have a wrapper.
581+
Adding '__new__' is done by function 'type_ready_set_new'. */
554582
ADD_SLOT_CONV("__free__", cls->tp_free, -1, JWRAPPER_DIRECT);
555583
ADD_SLOT_CONV("__del__", cls->tp_del, -1, JWRAPPER_DIRECT);
556584
ADD_SLOT_CONV("__finalize__", cls->tp_finalize, -1, JWRAPPER_DIRECT);
@@ -655,6 +683,9 @@ int PyType_Ready(PyTypeObject* cls) {
655683
inherit_slots(cls, (PyTypeObject *)b);
656684
}
657685

686+
ADD_IF_MISSING(cls, tp_alloc, PyType_GenericAlloc);
687+
ADD_IF_MISSING(cls, tp_new, PyType_GenericNew);
688+
658689
// process inherited slots
659690
// CPython doesn't do that in 'PyType_Ready' but we must because a native type can inherit
660691
// dynamic slots from a managed Python class. Since the managed Python class may be created

0 commit comments

Comments
 (0)