10
10
package org .truffleruby .core ;
11
11
12
12
import java .lang .ref .ReferenceQueue ;
13
+ import java .util .concurrent .locks .ReentrantLock ;
13
14
14
15
import org .truffleruby .RubyContext ;
15
16
import org .truffleruby .RubyLanguage ;
16
17
import org .truffleruby .cext .DataHolder ;
17
18
import org .truffleruby .core .MarkingService .ExtensionCallStack ;
19
+ import org .truffleruby .core .mutex .MutexOperations ;
18
20
import org .truffleruby .language .Nil ;
19
21
import org .truffleruby .language .RubyBaseRootNode ;
20
22
import org .truffleruby .language .backtrace .InternalRootNode ;
26
28
import com .oracle .truffle .api .interop .InteropLibrary ;
27
29
import com .oracle .truffle .api .interop .UnsupportedMessageException ;
28
30
import com .oracle .truffle .api .interop .UnsupportedTypeException ;
31
+ import com .oracle .truffle .api .profiles .ConditionProfile ;
29
32
import com .oracle .truffle .api .frame .VirtualFrame ;
30
33
31
34
/** Finalizers are implemented with phantom references and reference queues, and are run in a dedicated Ruby thread. */
@@ -36,6 +39,7 @@ public static class DataObjectFinalizerRootNode extends RubyBaseRootNode impleme
36
39
37
40
@ Child private InteropLibrary nullNode ;
38
41
@ Child private InteropLibrary callNode ;
42
+ private final ConditionProfile ownedProfile = ConditionProfile .create ();
39
43
40
44
public DataObjectFinalizerRootNode (
41
45
RubyLanguage language ) {
@@ -51,17 +55,44 @@ public Object execute(VirtualFrame frame) {
51
55
}
52
56
53
57
public Object execute (DataObjectFinalizerReference ref ) {
58
+ if (getContext ().getOptions ().CEXT_LOCK ) {
59
+ final ReentrantLock lock = getContext ().getCExtensionsLock ();
60
+ boolean owned = ownedProfile .profile (lock .isHeldByCurrentThread ());
61
+
62
+ if (!owned ) {
63
+ MutexOperations .lockInternal (getContext (), lock , this );
64
+ }
65
+ try {
66
+ runFinalizer (ref );
67
+ } finally {
68
+ if (!owned ) {
69
+ MutexOperations .unlockInternal (lock );
70
+ }
71
+ }
72
+ } else {
73
+ runFinalizer (ref );
74
+ }
75
+ return Nil .INSTANCE ;
76
+ }
77
+
78
+ private void runFinalizer (DataObjectFinalizerReference ref ) throws Error {
54
79
try {
55
80
if (!getContext ().isFinalizing ()) {
56
81
Object data = ref .dataHolder .getAddress ();
57
82
if (!nullNode .isNull (data )) {
58
- callNode .execute (ref .callable , data );
83
+ final ExtensionCallStack stack = getLanguage ().getCurrentThread ()
84
+ .getCurrentFiber ().extensionCallStack ;
85
+ stack .push (false , stack .getSpecialVariables (), stack .getBlock ());
86
+ try {
87
+ callNode .execute (ref .callable , data );
88
+ } finally {
89
+ stack .pop ();
90
+ }
59
91
}
60
92
}
61
93
} catch (UnsupportedTypeException | ArityException | UnsupportedMessageException e ) {
62
94
throw CompilerDirectives .shouldNotReachHere ("Data holder finalization on invalid object" );
63
95
}
64
- return Nil .INSTANCE ;
65
96
}
66
97
}
67
98
@@ -106,12 +137,6 @@ protected void processReference(RubyContext context, RubyLanguage language,
106
137
@ TruffleBoundary
107
138
protected void processReferenceInternal (RubyContext context , RubyLanguage language ,
108
139
DataObjectFinalizerReference ref ) {
109
- final ExtensionCallStack stack = language .getCurrentThread ().getCurrentFiber ().extensionCallStack ;
110
- stack .push (false , stack .getSpecialVariables (), stack .getBlock ());
111
- try {
112
- callTarget .call (new Object []{ ref });
113
- } finally {
114
- stack .pop ();
115
- }
140
+ callTarget .call (new Object []{ ref });
116
141
}
117
142
}
0 commit comments