41
41
package com .oracle .graal .python .builtins .objects .cext .capi ;
42
42
43
43
import static com .oracle .graal .python .PythonLanguage .CONTEXT_INSENSITIVE_SINGLETONS ;
44
+ import static com .oracle .graal .python .builtins .objects .cext .capi .PythonNativeWrapper .PythonAbstractObjectNativeWrapper .IMMORTAL_REFCNT ;
44
45
import static com .oracle .graal .python .nodes .SpecialAttributeNames .T___FILE__ ;
45
46
import static com .oracle .graal .python .nodes .SpecialAttributeNames .T___LIBRARY__ ;
46
47
import static com .oracle .graal .python .nodes .StringLiterals .J_LLVM_LANGUAGE ;
@@ -423,6 +424,29 @@ public PythonAbstractObjectNativeWrapper getSingletonNativeWrapper(PythonAbstrac
423
424
return null ;
424
425
}
425
426
427
+ /**
428
+ * Deallocates all singleton wrappers (in {@link #singletonNativePtrs}) which are immortal and
429
+ * must therefore be explicitly free'd. This method modifies the
430
+ * {@link HandleContext#nativeStubLookup stub lookup table} but runs not guest code.
431
+ */
432
+ private void freeSingletonNativeWrappers () {
433
+ CompilerAsserts .neverPartOfCompilation ();
434
+ // TODO(fa): this should not require the GIL (GR-51314)
435
+ assert getContext ().ownsGil ();
436
+ HandleContext nativeContext = getContext ().nativeContext ;
437
+ for (int i = 0 ; i < singletonNativePtrs .length ; i ++) {
438
+ PythonAbstractObjectNativeWrapper singletonNativeWrapper = singletonNativePtrs [i ];
439
+ singletonNativePtrs [i ] = null ;
440
+ assert singletonNativeWrapper != null ;
441
+ assert getSingletonNativeWrapperIdx (singletonNativeWrapper .getDelegate ()) != -1 ;
442
+ assert !singletonNativeWrapper .isNative () || singletonNativeWrapper .getRefCount () == IMMORTAL_REFCNT ;
443
+ if (singletonNativeWrapper .ref != null ) {
444
+ CApiTransitions .nativeStubLookupRemove (nativeContext , singletonNativeWrapper .ref );
445
+ }
446
+ PyTruffleObjectFree .releaseNativeWrapperUncached (singletonNativeWrapper );
447
+ }
448
+ }
449
+
426
450
public PrimitiveNativeWrapper getCachedPrimitiveNativeWrapper (int i ) {
427
451
assert CApiGuards .isSmallInteger (i );
428
452
PrimitiveNativeWrapper primitiveNativeWrapper = primitiveNativeWrapperCache [i + 5 ];
@@ -455,8 +479,16 @@ Object getOrCreateSmallInts() {
455
479
return nativeSmallIntsArray ;
456
480
}
457
481
482
+ /**
483
+ * Deallocates the native small int array (pointer {@link #nativeSmallIntsArray}) and all
484
+ * wrappers of the small ints (in {@link #primitiveNativeWrapperCache}) which are immortal and
485
+ * must therefore be explicitly free'd. This method modifies the
486
+ * {@link HandleContext#nativeStubLookup stub lookup table} but runs not guest code.
487
+ */
458
488
private void freeSmallInts () {
459
489
CompilerAsserts .neverPartOfCompilation ();
490
+ // TODO(fa): this should not require the GIL (GR-51314)
491
+ assert getContext ().ownsGil ();
460
492
if (nativeSmallIntsArray != null ) {
461
493
assert verifyNativeSmallInts ();
462
494
// free the native array used to store the stub pointers of the small int wrappers
@@ -466,7 +498,7 @@ private void freeSmallInts() {
466
498
HandleContext nativeContext = getContext ().nativeContext ;
467
499
for (PrimitiveNativeWrapper wrapper : primitiveNativeWrapperCache ) {
468
500
assert wrapper .isIntLike () && CApiGuards .isSmallLong (wrapper .getLong ());
469
- assert !wrapper .isNative () || wrapper .getRefCount () == PythonAbstractObjectNativeWrapper . IMMORTAL_REFCNT ;
501
+ assert !wrapper .isNative () || wrapper .getRefCount () == IMMORTAL_REFCNT ;
470
502
if (wrapper .ref != null ) {
471
503
CApiTransitions .nativeStubLookupRemove (nativeContext , wrapper .ref );
472
504
}
@@ -485,7 +517,7 @@ private boolean verifyNativeSmallInts() {
485
517
Object elementPtr = ReadPointerNode .getUncached ().readArrayElement (nativeSmallIntsArray , i );
486
518
PythonNativeWrapper wrapper = ToPythonWrapperNode .executeUncached (elementPtr , false );
487
519
if (!(wrapper == primitiveNativeWrapperCache [i ] && primitiveNativeWrapperCache [i ].isNative () &&
488
- primitiveNativeWrapperCache [i ].getRefCount () == PythonAbstractObjectNativeWrapper . IMMORTAL_REFCNT )) {
520
+ primitiveNativeWrapperCache [i ].getRefCount () == IMMORTAL_REFCNT )) {
489
521
return false ;
490
522
}
491
523
}
@@ -876,28 +908,14 @@ public void finalizeCapi() {
876
908
CApiTransitions .disableReferenceQueuePolling (getContext ().nativeContext );
877
909
// TODO(fa): remove GIL acquisition (GR-51314)
878
910
try (GilNode .UncachedAcquire gil = GilNode .uncachedAcquire ()) {
879
- HandleContext nativeContext = getContext ().nativeContext ;
880
911
freeSmallInts ();
881
- for (int i = 0 ; i < singletonNativePtrs .length ; i ++) {
882
- PythonNativeWrapper singletonNativeWrapper = singletonNativePtrs [i ];
883
- singletonNativePtrs [i ] = null ;
884
- assert singletonNativeWrapper != null ;
885
- if (singletonNativeWrapper .ref != null ) {
886
- CApiTransitions .nativeStubLookupRemove (nativeContext , singletonNativeWrapper .ref );
887
- }
888
- PyTruffleObjectFree .releaseNativeWrapperUncached (singletonNativeWrapper );
889
- }
912
+ freeSingletonNativeWrappers ();
890
913
/*
891
914
* Clear all remaining native object stubs. This must be done after the small int and
892
915
* the singleton wrappers were cleared because they might also end up in the lookup
893
916
* table and may otherwise be double-free'd.
894
917
*/
895
- for (PythonObjectReference ref : nativeContext .nativeStubLookup ) {
896
- if (ref != null ) {
897
- CApiTransitions .nativeStubLookupRemove (nativeContext , ref );
898
- CApiTransitions .freeNativeStub (ref );
899
- }
900
- }
918
+ freeNativeObjectStubs ();
901
919
}
902
920
if (pyDateTimeCAPICapsule != null ) {
903
921
PyDateTimeCAPIWrapper .destroyWrapper (pyDateTimeCAPICapsule );
@@ -928,6 +946,21 @@ public void finalizeCapi() {
928
946
}
929
947
}
930
948
949
+ /**
950
+ * Deallocates any native object stub that is still reachable via the
951
+ * {@link HandleContext#nativeStubLookup lookup table}. This method modifies the
952
+ * {@link HandleContext#nativeStubLookup stub lookup table} but runs not guest code.
953
+ */
954
+ private void freeNativeObjectStubs () {
955
+ HandleContext nativeContext = getContext ().nativeContext ;
956
+ for (PythonObjectReference ref : nativeContext .nativeStubLookup ) {
957
+ if (ref != null ) {
958
+ CApiTransitions .nativeStubLookupRemove (nativeContext , ref );
959
+ CApiTransitions .freeNativeStub (ref );
960
+ }
961
+ }
962
+ }
963
+
931
964
@ TruffleBoundary
932
965
public Object initCApiModule (Node location , Object sharedLibrary , TruffleString initFuncName , ModuleSpec spec , InteropLibrary llvmInteropLib , CheckFunctionResultNode checkFunctionResultNode )
933
966
throws UnsupportedMessageException , ArityException , UnsupportedTypeException , ImportException {
0 commit comments