@@ -178,34 +178,19 @@ void PyType_Modified(PyTypeObject* type) {
178
178
static void inherit_special (PyTypeObject * type , PyTypeObject * base ) {
179
179
180
180
/* 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 );
183
183
if (!(flags & Py_TPFLAGS_HAVE_GC ) &&
184
184
(base_flags & Py_TPFLAGS_HAVE_GC ) &&
185
185
(!PyTypeObject_tp_traverse (type ) && !PyTypeObject_tp_clear (type ))) {
186
- flags |= Py_TPFLAGS_HAVE_GC ;
186
+
187
+ flags |= Py_TPFLAGS_HAVE_GC ;
187
188
if (PyTypeObject_tp_traverse (type ) == NULL )
188
189
set_PyTypeObject_tp_traverse (type , PyTypeObject_tp_traverse (base ));
189
190
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 ));
208
192
}
193
+
209
194
/* Copy other non-function slots */
210
195
211
196
#undef COPYVAL
@@ -238,7 +223,7 @@ static void inherit_special(PyTypeObject *type, PyTypeObject *base) {
238
223
flags |= _Py_TPFLAGS_MATCH_SELF ;
239
224
240
225
if (flags != PyTypeObject_tp_flags (type )) {
241
- set_PyTypeObject_tp_flags (type , flags );
226
+ set_PyTypeObject_tp_flags (type , flags );
242
227
}
243
228
}
244
229
@@ -372,13 +357,55 @@ static void add_slot(PyTypeObject* cls, PyObject* type_dict, char* name, void* m
372
357
}
373
358
}
374
359
375
- #define ADD_MEMBER (__javacls__ , __tpdict__ , __mname__ , __mtype__ , __moffset__ , __mflags__ , __mdoc__ ) \
360
+ #define ADD_MEMBER (__javacls__ , __tpdict__ , __mname__ , __mtype__ , __moffset__ , __mflags__ , __mdoc__ ) \
376
361
add_member((__javacls__), (__tpdict__), (__mname__), (__mtype__), (__moffset__), (__mflags__), (__mdoc__))
377
362
378
363
379
- #define ADD_GETSET (__javacls__ , __tpdict__ , __name__ , __getter__ , __setter__ , __doc__ , __closure__ ) \
364
+ #define ADD_GETSET (__javacls__ , __tpdict__ , __name__ , __getter__ , __setter__ , __doc__ , __closure__ ) \
380
365
add_getset((__javacls__), (__tpdict__), (__name__), (__getter__), (__setter__), (__doc__), (__closure__))
381
366
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
+ }
382
409
383
410
int PyType_Ready (PyTypeObject * cls ) {
384
411
#define RETURN_ERROR (__type__ ) \
@@ -388,7 +415,7 @@ int PyType_Ready(PyTypeObject* cls) {
388
415
return -1; \
389
416
} while(0)
390
417
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)) ; }
392
419
#define ADD_SLOT_CONV (__name__ , __meth__ , __flags__ , __signature__ ) add_slot(cls, dict, (__name__), (__meth__), (__flags__), (__signature__), NULL)
393
420
394
421
Py_ssize_t n ;
@@ -507,23 +534,15 @@ int PyType_Ready(PyTypeObject* cls) {
507
534
PyObject * mro = GraalPyTruffle_Compute_Mro (cls , truffleString (cls -> tp_name ));
508
535
set_PyTypeObject_tp_mro (cls , mro );
509
536
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 );
513
539
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 */
524
541
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
+ */
527
546
528
547
// add special methods defined directly on the type structs
529
548
ADD_SLOT_CONV ("__dealloc__" , cls -> tp_dealloc , -1 , JWRAPPER_DIRECT );
@@ -563,25 +582,14 @@ int PyType_Ready(PyTypeObject* cls) {
563
582
ADD_SLOT_CONV ("__set__" , cls -> tp_descr_set , -3 , JWRAPPER_DESCR_SET );
564
583
ADD_SLOT_CONV ("__init__" , cls -> tp_init , METH_KEYWORDS | METH_VARARGS , JWRAPPER_INITPROC );
565
584
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'. */
567
588
ADD_SLOT_CONV ("__free__" , cls -> tp_free , -1 , JWRAPPER_DIRECT );
568
589
ADD_SLOT_CONV ("__del__" , cls -> tp_del , -1 , JWRAPPER_DIRECT );
569
590
ADD_SLOT_CONV ("__finalize__" , cls -> tp_finalize , -1 , JWRAPPER_DIRECT );
570
591
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' !
585
593
PyNumberMethods * numbers = PyTypeObject_tp_as_number (cls );
586
594
if (numbers ) {
587
595
ADD_SLOT_CONV ("__add__" , numbers -> nb_add , -2 , JWRAPPER_BINARYFUNC_L );
@@ -635,6 +643,7 @@ int PyType_Ready(PyTypeObject* cls) {
635
643
ADD_SLOT_CONV ("__imatmul__" , numbers -> nb_inplace_matrix_multiply , -2 , JWRAPPER_BINARYFUNC_L );
636
644
}
637
645
646
+ // 'tp_as_mapping' takes precedence over 'tp_as_sequence' !
638
647
PyMappingMethods * mappings = PyTypeObject_tp_as_mapping (cls );
639
648
if (mappings ) {
640
649
ADD_SLOT_CONV ("__len__" , mappings -> mp_length , -1 , JWRAPPER_LENFUNC );
@@ -643,6 +652,20 @@ int PyType_Ready(PyTypeObject* cls) {
643
652
ADD_SLOT_CONV ("__delitem__" , mappings -> mp_ass_subscript , -3 , JWRAPPER_MP_DELITEM );
644
653
}
645
654
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
+
646
669
PyAsyncMethods * async = PyTypeObject_tp_as_async (cls );
647
670
if (async ) {
648
671
ADD_SLOT_CONV ("__await__" , async -> am_await , -1 , JWRAPPER_DIRECT );
@@ -655,6 +678,22 @@ int PyType_Ready(PyTypeObject* cls) {
655
678
// TODO ...
656
679
}
657
680
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
+
658
697
// process inherited slots
659
698
// CPython doesn't do that in 'PyType_Ready' but we must because a native type can inherit
660
699
// dynamic slots from a managed Python class. Since the managed Python class may be created
0 commit comments