@@ -511,17 +511,26 @@ PyObject *JSArrayProxyMethodDefinitions::JSArrayProxy_richcompare(JSArrayProxy *
511
511
}
512
512
513
513
PyObject *JSArrayProxyMethodDefinitions::JSArrayProxy_repr (JSArrayProxy *self) {
514
+ // Detect cyclic objects
515
+ PyObject *objPtr = PyLong_FromVoidPtr (self->jsArray ->get ());
516
+ // For `Py_ReprEnter`, we must get a same PyObject when visiting the same JSObject.
517
+ // We cannot simply use the object returned by `PyLong_FromVoidPtr` because it won't reuse the PyLongObjects for ints not between -5 and 256.
518
+ // Instead, we store this PyLongObject in a global dict, using itself as the hashable key, effectively interning the PyLongObject.
519
+ PyObject *tsDict = PyThreadState_GetDict ();
520
+ PyObject *cyclicKey = PyDict_SetDefault (tsDict, /* key*/ objPtr, /* value*/ objPtr); // cyclicKey = (tsDict[objPtr] ??= objPtr)
521
+ int i = Py_ReprEnter (cyclicKey);
522
+ if (i != 0 ) {
523
+ return i > 0 ? PyUnicode_FromString (" [...]" ) : NULL ;
524
+ }
525
+
514
526
Py_ssize_t selfLength = JSArrayProxy_length (self);
515
527
516
528
if (selfLength == 0 ) {
529
+ Py_ReprLeave (cyclicKey);
530
+ PyDict_DelItem (tsDict, cyclicKey);
517
531
return PyUnicode_FromString (" []" );
518
532
}
519
533
520
- Py_ssize_t i = Py_ReprEnter ((PyObject *)self);
521
- if (i != 0 ) {
522
- return i > 0 ? PyUnicode_FromString (" [...]" ) : NULL ;
523
- }
524
-
525
534
_PyUnicodeWriter writer;
526
535
527
536
_PyUnicodeWriter_Init (&writer);
@@ -569,12 +578,14 @@ PyObject *JSArrayProxyMethodDefinitions::JSArrayProxy_repr(JSArrayProxy *self) {
569
578
goto error;
570
579
}
571
580
572
- Py_ReprLeave ((PyObject *)self);
581
+ Py_ReprLeave (cyclicKey);
582
+ PyDict_DelItem (tsDict, cyclicKey);
573
583
return _PyUnicodeWriter_Finish (&writer);
574
584
575
585
error:
576
586
_PyUnicodeWriter_Dealloc (&writer);
577
- Py_ReprLeave ((PyObject *)self);
587
+ Py_ReprLeave (cyclicKey);
588
+ PyDict_DelItem (tsDict, cyclicKey);
578
589
return NULL ;
579
590
}
580
591
0 commit comments