81
81
import com .oracle .graal .python .builtins .objects .cext .capi .transitions .CApiTransitions ;
82
82
import com .oracle .graal .python .builtins .objects .cext .capi .transitions .CApiTransitions .HandleContext ;
83
83
import com .oracle .graal .python .builtins .objects .cext .capi .transitions .CApiTransitions .NativeToPythonNode ;
84
- import com .oracle .graal .python .builtins .objects .cext .capi .transitions .CApiTransitions .PythonObjectReference ;
85
84
import com .oracle .graal .python .builtins .objects .cext .capi .transitions .CApiTransitions .ToPythonWrapperNode ;
86
85
import com .oracle .graal .python .builtins .objects .cext .common .CExtCommonNodes .CheckFunctionResultNode ;
87
86
import com .oracle .graal .python .builtins .objects .cext .common .CExtContext ;
124
123
import com .oracle .truffle .api .TruffleFile ;
125
124
import com .oracle .truffle .api .TruffleLanguage .Env ;
126
125
import com .oracle .truffle .api .TruffleLogger ;
126
+ import com .oracle .truffle .api .TruffleSafepoint ;
127
127
import com .oracle .truffle .api .frame .VirtualFrame ;
128
128
import com .oracle .truffle .api .interop .ArityException ;
129
129
import com .oracle .truffle .api .interop .InteropLibrary ;
@@ -429,19 +429,18 @@ public PythonAbstractObjectNativeWrapper getSingletonNativeWrapper(PythonAbstrac
429
429
* must therefore be explicitly free'd. This method modifies the
430
430
* {@link HandleContext#nativeStubLookup stub lookup table} but runs not guest code.
431
431
*/
432
- private void freeSingletonNativeWrappers () {
432
+ private void freeSingletonNativeWrappers (HandleContext handleContext ) {
433
433
CompilerAsserts .neverPartOfCompilation ();
434
434
// TODO(fa): this should not require the GIL (GR-51314)
435
435
assert getContext ().ownsGil ();
436
- HandleContext nativeContext = getContext ().nativeContext ;
437
436
for (int i = 0 ; i < singletonNativePtrs .length ; i ++) {
438
437
PythonAbstractObjectNativeWrapper singletonNativeWrapper = singletonNativePtrs [i ];
439
438
singletonNativePtrs [i ] = null ;
440
439
assert singletonNativeWrapper != null ;
441
440
assert getSingletonNativeWrapperIdx (singletonNativeWrapper .getDelegate ()) != -1 ;
442
441
assert !singletonNativeWrapper .isNative () || singletonNativeWrapper .getRefCount () == IMMORTAL_REFCNT ;
443
442
if (singletonNativeWrapper .ref != null ) {
444
- CApiTransitions .nativeStubLookupRemove (nativeContext , singletonNativeWrapper .ref );
443
+ CApiTransitions .nativeStubLookupRemove (handleContext , singletonNativeWrapper .ref );
445
444
}
446
445
PyTruffleObjectFree .releaseNativeWrapperUncached (singletonNativeWrapper );
447
446
}
@@ -485,7 +484,7 @@ Object getOrCreateSmallInts() {
485
484
* must therefore be explicitly free'd. This method modifies the
486
485
* {@link HandleContext#nativeStubLookup stub lookup table} but runs not guest code.
487
486
*/
488
- private void freeSmallInts () {
487
+ private void freeSmallInts (HandleContext handleContext ) {
489
488
CompilerAsserts .neverPartOfCompilation ();
490
489
// TODO(fa): this should not require the GIL (GR-51314)
491
490
assert getContext ().ownsGil ();
@@ -495,12 +494,11 @@ private void freeSmallInts() {
495
494
FreeNode .executeUncached (nativeSmallIntsArray );
496
495
nativeSmallIntsArray = null ;
497
496
}
498
- HandleContext nativeContext = getContext ().nativeContext ;
499
497
for (PrimitiveNativeWrapper wrapper : primitiveNativeWrapperCache ) {
500
498
assert wrapper .isIntLike () && CApiGuards .isSmallLong (wrapper .getLong ());
501
499
assert !wrapper .isNative () || wrapper .getRefCount () == IMMORTAL_REFCNT ;
502
500
if (wrapper .ref != null ) {
503
- CApiTransitions .nativeStubLookupRemove (nativeContext , wrapper .ref );
501
+ CApiTransitions .nativeStubLookupRemove (handleContext , wrapper .ref );
504
502
}
505
503
PyTruffleObjectFree .releaseNativeWrapperUncached (wrapper );
506
504
}
@@ -897,28 +895,63 @@ private void addNativeFinalizer(Env env, Object resetFunctionPointerArray) {
897
895
}
898
896
}
899
897
900
- @ TruffleBoundary
901
- @ SuppressWarnings ("try" )
902
- public void finalizeCapi () {
898
+ /**
899
+ * This method is called to exit the context assuming a
900
+ * {@link com.oracle.truffle.api.TruffleLanguage.ExitMode#NATURAL natural exit}. This means, it
901
+ * is allowed to run guest code. Hence, we deallocate any reachable native object here since
902
+ * they may have custom {@code tp_dealloc} functions.
903
+ */
904
+ public void exitCApiContext () {
905
+ CompilerAsserts .neverPartOfCompilation ();
906
+ /*
907
+ * Polling the native reference queue is the only task we can do here because deallocating
908
+ * objects may run arbitrary guest code that can again call into the interpreter.
909
+ */
910
+ CApiTransitions .pollReferenceQueue ();
911
+ /*
912
+ * Deallocating native storages and objects may run arbitrary guest code. So, we need to
913
+ * ensure that the GIL is held.
914
+ */
915
+ try (GilNode .UncachedAcquire ignored = GilNode .uncachedAcquire ()) {
916
+ CApiTransitions .deallocateNativeWeakRefs (getContext ());
917
+ }
918
+ }
919
+
920
+ public void finalizeCApi () {
921
+ CompilerAsserts .neverPartOfCompilation ();
922
+ HandleContext handleContext = getContext ().nativeContext ;
903
923
/*
904
924
* Disable reference queue polling because during finalization, we will free any known
905
925
* allocated resources (e.g. native object stubs). Calling
906
926
* 'CApiTransitions.pollReferenceQueue' could then lead to a double-free.
907
927
*/
908
- CApiTransitions .disableReferenceQueuePolling (getContext ().nativeContext );
909
- // TODO(fa): remove GIL acquisition (GR-51314)
910
- try (GilNode .UncachedAcquire gil = GilNode .uncachedAcquire ()) {
911
- freeSmallInts ();
912
- freeSingletonNativeWrappers ();
913
- /*
914
- * Clear all remaining native object stubs. This must be done after the small int and
915
- * the singleton wrappers were cleared because they might also end up in the lookup
916
- * table and may otherwise be double-free'd.
917
- */
918
- freeNativeObjectStubs ();
919
- }
920
- if (pyDateTimeCAPICapsule != null ) {
921
- PyDateTimeCAPIWrapper .destroyWrapper (pyDateTimeCAPICapsule );
928
+ CApiTransitions .disableReferenceQueuePolling (handleContext );
929
+
930
+ TruffleSafepoint sp = TruffleSafepoint .getCurrent ();
931
+ boolean prev = sp .setAllowActions (false );
932
+ try {
933
+ // TODO(fa): remove GIL acquisition (GR-51314)
934
+ try (GilNode .UncachedAcquire ignored = GilNode .uncachedAcquire ()) {
935
+ freeSmallInts (handleContext );
936
+ freeSingletonNativeWrappers (handleContext );
937
+ /*
938
+ * Clear all remaining native object stubs. This must be done after the small int
939
+ * and the singleton wrappers were cleared because they might also end up in the
940
+ * lookup table and may otherwise be double-freed.
941
+ */
942
+ CApiTransitions .freeNativeObjectStubs (handleContext );
943
+ CApiTransitions .freeClassReplacements (handleContext );
944
+ CApiTransitions .freeNativeStorages (handleContext );
945
+ }
946
+ if (pyDateTimeCAPICapsule != null ) {
947
+ PyDateTimeCAPIWrapper .destroyWrapper (pyDateTimeCAPICapsule );
948
+ }
949
+ // free all allocated PyMethodDef structures
950
+ for (Object pyMethodDefPointer : methodDefinitions .values ()) {
951
+ PyMethodDefHelper .free (pyMethodDefPointer );
952
+ }
953
+ } finally {
954
+ sp .setAllowActions (prev );
922
955
}
923
956
if (nativeFinalizerShutdownHook != null ) {
924
957
try {
@@ -929,10 +962,6 @@ public void finalizeCapi() {
929
962
}
930
963
}
931
964
pyCFunctionWrappers .clear ();
932
- // free all allocated PyMethodDef structures
933
- for (Object pyMethodDefPointer : methodDefinitions .values ()) {
934
- PyMethodDefHelper .free (pyMethodDefPointer );
935
- }
936
965
/*
937
966
* If the static symbol cache is not null, then it is guaranteed that this context instance
938
967
* was the exclusive user of it. We can now reset the state such that other contexts created
@@ -946,21 +975,6 @@ public void finalizeCapi() {
946
975
}
947
976
}
948
977
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
-
964
978
@ TruffleBoundary
965
979
public Object initCApiModule (Node location , Object sharedLibrary , TruffleString initFuncName , ModuleSpec spec , InteropLibrary llvmInteropLib , CheckFunctionResultNode checkFunctionResultNode )
966
980
throws UnsupportedMessageException , ArityException , UnsupportedTypeException , ImportException {
0 commit comments