@@ -178,34 +178,19 @@ void PyType_Modified(PyTypeObject* type) {
178178static 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
383410int 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,23 +534,15 @@ 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- /* Inherit special flags from dominant base */
511- if (base != NULL )
512- inherit_special (cls , base );
537+ /* set new */
538+ type_ready_set_new (cls , dict , base );
513539
514- /* Initialize tp_dict properly */
515- bases = mro ;
516- assert (bases != NULL );
517- assert (PyTuple_Check (bases ));
518- n = PyTuple_GET_SIZE (bases );
519- for (i = 1 ; i < n ; i ++ ) {
520- PyObject * b = PyTuple_GET_ITEM (bases , i );
521- if (PyType_Check (b ))
522- inherit_slots (cls , (PyTypeObject * )b );
523- }
540+ /* fill dict */
524541
525- ADD_IF_MISSING (cls -> tp_alloc , PyType_GenericAlloc );
526- ADD_IF_MISSING (cls -> tp_new , PyType_GenericNew );
542+ /*
543+ * NOTE: ADD_SLOT_CONV won't overwrite existing attributes, so the order is crucial and must
544+ * reflect CPython's 'slotdefs' array.
545+ */
527546
528547 // add special methods defined directly on the type structs
529548 ADD_SLOT_CONV ("__dealloc__" , cls -> tp_dealloc , -1 , JWRAPPER_DIRECT );
@@ -563,25 +582,14 @@ int PyType_Ready(PyTypeObject* cls) {
563582 ADD_SLOT_CONV ("__set__" , cls -> tp_descr_set , -3 , JWRAPPER_DESCR_SET );
564583 ADD_SLOT_CONV ("__init__" , cls -> tp_init , METH_KEYWORDS | METH_VARARGS , JWRAPPER_INITPROC );
565584 ADD_SLOT_CONV ("__alloc__" , cls -> tp_alloc , -2 , JWRAPPER_ALLOC );
566- ADD_SLOT_CONV ("__new__" , cls -> tp_new , METH_KEYWORDS | METH_VARARGS , JWRAPPER_NEW );
585+ /* Note: '__new__' was added here previously but we don't do it similar to CPython.
586+ They also skip it because the appropriate 'slotdef' doesn't have a wrapper.
587+ Adding '__new__' is done by function 'type_ready_set_new'. */
567588 ADD_SLOT_CONV ("__free__" , cls -> tp_free , -1 , JWRAPPER_DIRECT );
568589 ADD_SLOT_CONV ("__del__" , cls -> tp_del , -1 , JWRAPPER_DIRECT );
569590 ADD_SLOT_CONV ("__finalize__" , cls -> tp_finalize , -1 , JWRAPPER_DIRECT );
570591
571- PySequenceMethods * sequences = PyTypeObject_tp_as_sequence (cls );
572- if (sequences ) {
573- // sequence functions first, so that the number functions take precendence
574- ADD_SLOT_CONV ("__len__" , sequences -> sq_length , -1 , JWRAPPER_LENFUNC );
575- ADD_SLOT_CONV ("__add__" , sequences -> sq_concat , -2 , JWRAPPER_BINARYFUNC );
576- ADD_SLOT_CONV ("__mul__" , sequences -> sq_repeat , -2 , JWRAPPER_SSIZE_ARG );
577- ADD_SLOT_CONV ("__getitem__" , sequences -> sq_item , -2 , JWRAPPER_GETITEM );
578- ADD_SLOT_CONV ("__setitem__" , sequences -> sq_ass_item , -3 , JWRAPPER_SETITEM );
579- ADD_SLOT_CONV ("__delitem__" , sequences -> sq_ass_item , -3 , JWRAPPER_DELITEM );
580- ADD_SLOT_CONV ("__contains__" , sequences -> sq_contains , -2 , JWRAPPER_OBJOBJPROC );
581- ADD_SLOT_CONV ("__iadd__" , sequences -> sq_inplace_concat , -2 , JWRAPPER_BINARYFUNC );
582- ADD_SLOT_CONV ("__imul__" , sequences -> sq_inplace_repeat , -2 , JWRAPPER_SSIZE_ARG );
583- }
584-
592+ // 'tp_as_number' takes precedence over 'tp_as_mapping' and 'tp_as_sequence' !
585593 PyNumberMethods * numbers = PyTypeObject_tp_as_number (cls );
586594 if (numbers ) {
587595 ADD_SLOT_CONV ("__add__" , numbers -> nb_add , -2 , JWRAPPER_BINARYFUNC_L );
@@ -635,6 +643,7 @@ int PyType_Ready(PyTypeObject* cls) {
635643 ADD_SLOT_CONV ("__imatmul__" , numbers -> nb_inplace_matrix_multiply , -2 , JWRAPPER_BINARYFUNC_L );
636644 }
637645
646+ // 'tp_as_mapping' takes precedence over 'tp_as_sequence' !
638647 PyMappingMethods * mappings = PyTypeObject_tp_as_mapping (cls );
639648 if (mappings ) {
640649 ADD_SLOT_CONV ("__len__" , mappings -> mp_length , -1 , JWRAPPER_LENFUNC );
@@ -643,6 +652,20 @@ int PyType_Ready(PyTypeObject* cls) {
643652 ADD_SLOT_CONV ("__delitem__" , mappings -> mp_ass_subscript , -3 , JWRAPPER_MP_DELITEM );
644653 }
645654
655+ PySequenceMethods * sequences = PyTypeObject_tp_as_sequence (cls );
656+ if (sequences ) {
657+ // sequence functions first, so that the number functions take precendence
658+ ADD_SLOT_CONV ("__len__" , sequences -> sq_length , -1 , JWRAPPER_LENFUNC );
659+ ADD_SLOT_CONV ("__add__" , sequences -> sq_concat , -2 , JWRAPPER_BINARYFUNC );
660+ ADD_SLOT_CONV ("__mul__" , sequences -> sq_repeat , -2 , JWRAPPER_SSIZE_ARG );
661+ ADD_SLOT_CONV ("__getitem__" , sequences -> sq_item , -2 , JWRAPPER_GETITEM );
662+ ADD_SLOT_CONV ("__setitem__" , sequences -> sq_ass_item , -3 , JWRAPPER_SETITEM );
663+ ADD_SLOT_CONV ("__delitem__" , sequences -> sq_ass_item , -3 , JWRAPPER_DELITEM );
664+ ADD_SLOT_CONV ("__contains__" , sequences -> sq_contains , -2 , JWRAPPER_OBJOBJPROC );
665+ ADD_SLOT_CONV ("__iadd__" , sequences -> sq_inplace_concat , -2 , JWRAPPER_BINARYFUNC );
666+ ADD_SLOT_CONV ("__imul__" , sequences -> sq_inplace_repeat , -2 , JWRAPPER_SSIZE_ARG );
667+ }
668+
646669 PyAsyncMethods * async = PyTypeObject_tp_as_async (cls );
647670 if (async ) {
648671 ADD_SLOT_CONV ("__await__" , async -> am_await , -1 , JWRAPPER_DIRECT );
@@ -655,6 +678,22 @@ int PyType_Ready(PyTypeObject* cls) {
655678 // TODO ...
656679 }
657680
681+ /* Inherit slots */
682+ if (base != NULL )
683+ inherit_special (cls , base );
684+ bases = mro ;
685+ assert (bases != NULL );
686+ assert (PyTuple_Check (bases ));
687+ n = PyTuple_GET_SIZE (bases );
688+ for (i = 1 ; i < n ; i ++ ) {
689+ PyObject * b = PyTuple_GET_ITEM (bases , i );
690+ if (PyType_Check (b ))
691+ inherit_slots (cls , (PyTypeObject * )b );
692+ }
693+
694+ ADD_IF_MISSING (cls , tp_alloc , PyType_GenericAlloc );
695+ ADD_IF_MISSING (cls , tp_new , PyType_GenericNew );
696+
658697 // process inherited slots
659698 // CPython doesn't do that in 'PyType_Ready' but we must because a native type can inherit
660699 // dynamic slots from a managed Python class. Since the managed Python class may be created
0 commit comments