3030import com .oracle .truffle .api .dsl .Specialization ;
3131import com .oracle .truffle .api .library .CachedLibrary ;
3232import com .oracle .truffle .api .nodes .ExplodeLoop ;
33+ import com .oracle .truffle .api .profiles .BranchProfile ;
3334import com .oracle .truffle .r .runtime .Collections .StackLibrary ;
3435import com .oracle .truffle .r .runtime .RError ;
3536import com .oracle .truffle .r .runtime .context .RContext ;
3637import com .oracle .truffle .r .runtime .context .TruffleRLanguage ;
3738import com .oracle .truffle .r .runtime .data .RNull ;
39+ import com .oracle .truffle .r .runtime .ffi .RFFIContext ;
40+ import com .oracle .truffle .r .runtime .ffi .RFFILog ;
3841
3942@ GenerateUncached
4043public abstract class UnprotectNode extends FFIUpCallNode .Arg1 {
@@ -54,11 +57,13 @@ Object unprotectNothing(@SuppressWarnings("unused") int n) {
5457
5558 @ Specialization (guards = "n == 1" )
5659 Object unprotectSingle (@ SuppressWarnings ("unused" ) int n ,
60+ @ Cached BranchProfile registerNativeRefProfile ,
5761 @ CachedContext (TruffleRLanguage .class ) ContextReference <RContext > ctxRef ,
5862 @ CachedLibrary (limit = "1" ) StackLibrary stacks ) {
5963 RContext ctx = ctxRef .get ();
64+ RFFIContext rffiCtx = ctx .getRFFI ();
6065 try {
61- stacks . pop (ctx . getStateRFFI (). rffiContextState . protectStack );
66+ popProtectedObject (ctx , rffiCtx , stacks , registerNativeRefProfile );
6267 } catch (IndexOutOfBoundsException e ) {
6368 debugWarning ("mismatched protect/unprotect (unprotect with empty protect stack)" );
6469 }
@@ -69,12 +74,14 @@ Object unprotectSingle(@SuppressWarnings("unused") int n,
6974 @ ExplodeLoop
7075 Object unprotectMultipleCached (@ SuppressWarnings ("unused" ) int n ,
7176 @ Cached ("n" ) int nCached ,
77+ @ Cached BranchProfile registerNativeRefProfile ,
7278 @ CachedContext (TruffleRLanguage .class ) ContextReference <RContext > ctxRef ,
7379 @ CachedLibrary (limit = "1" ) StackLibrary stacks ) {
7480 RContext ctx = ctxRef .get ();
81+ RFFIContext rffiCtx = ctx .getRFFI ();
7582 try {
7683 for (int i = 0 ; i < nCached ; i ++) {
77- stacks . pop (ctx . getStateRFFI (). rffiContextState . protectStack );
84+ popProtectedObject (ctx , rffiCtx , stacks , registerNativeRefProfile );
7885 }
7986 } catch (IndexOutOfBoundsException e ) {
8087 debugWarning ("mismatched protect/unprotect (unprotect with empty protect stack)" );
@@ -84,19 +91,31 @@ Object unprotectMultipleCached(@SuppressWarnings("unused") int n,
8491
8592 @ Specialization (guards = "n > 1" , replaces = "unprotectMultipleCached" )
8693 Object unprotectMultipleUnchached (int n ,
94+ @ Cached BranchProfile registerNativeRefProfile ,
8795 @ CachedContext (TruffleRLanguage .class ) ContextReference <RContext > ctxRef ,
8896 @ CachedLibrary (limit = "1" ) StackLibrary stacks ) {
8997 RContext ctx = ctxRef .get ();
98+ RFFIContext rffiCtx = ctx .getRFFI ();
9099 try {
91100 for (int i = 0 ; i < n ; i ++) {
92- stacks . pop (ctx . getStateRFFI (). rffiContextState . protectStack );
101+ popProtectedObject (ctx , rffiCtx , stacks , registerNativeRefProfile );
93102 }
94103 } catch (IndexOutOfBoundsException e ) {
95104 debugWarning ("mismatched protect/unprotect (unprotect with empty protect stack)" );
96105 }
97106 return RNull .instance ;
98107 }
99108
109+ private static void popProtectedObject (RContext ctx , RFFIContext rffiCtx , StackLibrary stacks , BranchProfile registerNativeRefProfile ) {
110+ Object removed = stacks .pop (ctx .getStateRFFI ().rffiContextState .protectStack );
111+ // Developers expect the "unprotected" references to be still alive until next GNU-R
112+ // compatible GC cycle
113+ rffiCtx .registerReferenceUsedInNative (removed , registerNativeRefProfile );
114+ if (RFFILog .logEnabled ()) {
115+ RFFILog .logRObject ("Unprotected: " , removed );
116+ }
117+ }
118+
100119 private static boolean debugWarning (String message ) {
101120 CompilerDirectives .transferToInterpreter ();
102121 RError .warning (RError .SHOW_CALLER , RError .Message .GENERIC , message );
0 commit comments