2929
3030import java .util .concurrent .atomic .AtomicInteger ;
3131
32- import jdk .graal .compiler .word .Word ;
3332import org .graalvm .nativeimage .CurrentIsolate ;
3433import org .graalvm .nativeimage .ImageSingletons ;
3534import org .graalvm .nativeimage .IsolateThread ;
5352import com .oracle .svm .core .log .Log ;
5453import com .oracle .svm .core .nodes .CFunctionEpilogueNode ;
5554import com .oracle .svm .core .nodes .CFunctionPrologueNode ;
56- import com .oracle .svm .core .nodes .CodeSynchronizationNode ;
5755import com .oracle .svm .core .nodes .SafepointCheckNode ;
5856import com .oracle .svm .core .option .HostedOptionKey ;
5957import com .oracle .svm .core .option .RuntimeOptionKey ;
8179import jdk .graal .compiler .nodes .extended .ForeignCallNode ;
8280import jdk .graal .compiler .nodes .extended .MembarNode ;
8381import jdk .graal .compiler .options .Option ;
82+ import jdk .graal .compiler .word .Word ;
8483
8584/**
8685 * Support for initiating safepoints, which are a global state in which all threads are paused so
@@ -151,14 +150,13 @@ public final class Safepoint {
151150 public static final SubstrateForeignCallDescriptor ENTER_SLOW_PATH_SAFEPOINT_CHECK = SnippetRuntime .findForeignCall (Safepoint .class , "enterSlowPathSafepointCheck" , NO_SIDE_EFFECT );
152151 public static final SubstrateForeignCallDescriptor ENTER_SLOW_PATH_TRANSITION_FROM_NATIVE_TO_NEW_STATUS = SnippetRuntime .findForeignCall (Safepoint .class ,
153152 "enterSlowPathTransitionFromNativeToNewStatus" , NO_SIDE_EFFECT );
154- private static final SubstrateForeignCallDescriptor ENTER_SLOW_PATH_TRANSITION_FROM_VM_TO_JAVA = SnippetRuntime .findForeignCall (Safepoint .class , "enterSlowPathTransitionFromVMToJava" ,
155- NO_SIDE_EFFECT );
153+ private static final SubstrateForeignCallDescriptor ENTER_SLOW_PATH_RUN_PENDING_ACTIONS = SnippetRuntime .findForeignCall (Safepoint .class , "enterSlowPathRunPendingActions" , NO_SIDE_EFFECT );
156154
157155 /** All foreign calls defined in this class. */
158156 public static final SubstrateForeignCallDescriptor [] FOREIGN_CALLS = new SubstrateForeignCallDescriptor []{
159157 ENTER_SLOW_PATH_SAFEPOINT_CHECK ,
160158 ENTER_SLOW_PATH_TRANSITION_FROM_NATIVE_TO_NEW_STATUS ,
161- ENTER_SLOW_PATH_TRANSITION_FROM_VM_TO_JAVA ,
159+ ENTER_SLOW_PATH_RUN_PENDING_ACTIONS ,
162160 };
163161
164162 /** Private constructor: No instances: only statics. */
@@ -250,32 +248,12 @@ private static void slowPathSafepointCheck0(int newStatus, boolean callerHasJava
250248 }
251249
252250 if (newStatus == StatusSupport .STATUS_IN_JAVA ) {
253- // Resetting the safepoint counter or executing the recurring callback must only be done
254- // if the thread is in Java state.
255- slowPathRunJavaStateActions ();
251+ ActionOnTransitionToJavaSupport . runPendingActions ();
252+ /* Do this last so that a thrown exception cannot skip any of the above. */
253+ ThreadingSupportImpl . onSafepointCheckSlowpath ();
256254 }
257255 }
258256
259- /**
260- * Slow path code run after a safepoint check or after transitioning from VM to Java state. It
261- * resets the safepoint counter, runs recurring callbacks if necessary, and executes pending
262- * {@link ActionOnTransitionToJavaSupport transition actions}.
263- */
264- @ Uninterruptible (reason = "Must not contain safepoint checks." )
265- private static void slowPathRunJavaStateActions () {
266- if (ActionOnTransitionToJavaSupport .isActionPending ()) {
267- if (ActionOnTransitionToJavaSupport .isSynchronizeCode ()) {
268- CodeSynchronizationNode .synchronizeCode ();
269- } else {
270- assert false : "Unexpected action pending." ;
271- }
272- ActionOnTransitionToJavaSupport .clearActions ();
273- }
274-
275- // Do this last so an exception cannot skip the above
276- ThreadingSupportImpl .onSafepointCheckSlowpath ();
277- }
278-
279257 @ NeverInline ("Must not be inlined in a caller that has an exception handler: We only support InvokeNode and not InvokeWithExceptionNode between a CFunctionPrologueNode and CFunctionEpilogueNode" )
280258 @ Uninterruptible (reason = "Must not contain safepoint checks." )
281259 private static void freezeAtSafepoint (int newStatus , boolean callerHasJavaFrameAnchor ) {
@@ -457,7 +435,7 @@ public static void transitionNativeToJava(boolean popFrameAnchor) {
457435 JavaFrameAnchors .popFrameAnchor ();
458436 }
459437 } else {
460- callSlowPathNativeToNewStatus (Safepoint . ENTER_SLOW_PATH_TRANSITION_FROM_NATIVE_TO_NEW_STATUS , newStatus , popFrameAnchor );
438+ callSlowPathNativeToNewStatus (ENTER_SLOW_PATH_TRANSITION_FROM_NATIVE_TO_NEW_STATUS , newStatus , popFrameAnchor );
461439 }
462440
463441 /*
@@ -479,22 +457,23 @@ public static void slowTransitionNativeToVM() {
479457 int newStatus = StatusSupport .STATUS_IN_VM ;
480458 boolean needSlowPath = !StatusSupport .compareAndSetNativeToNewStatus (newStatus );
481459 if (BranchProbabilityNode .probability (BranchProbabilityNode .VERY_SLOW_PATH_PROBABILITY , needSlowPath )) {
482- callSlowPathNativeToNewStatus (Safepoint . ENTER_SLOW_PATH_TRANSITION_FROM_NATIVE_TO_NEW_STATUS , newStatus , false );
460+ callSlowPathNativeToNewStatus (ENTER_SLOW_PATH_TRANSITION_FROM_NATIVE_TO_NEW_STATUS , newStatus , false );
483461 }
484462 }
485463
486464 @ Uninterruptible (reason = "Must not contain safepoint checks" )
487465 public static void transitionVMToJava (boolean popFrameAnchor ) {
488- // We can directly change the thread status as no other thread will touch the status field
489- // as long as we are in VM status.
466+ /* Change the thread status directly (other threads won't touch the status field). */
490467 StatusSupport .assertStatusVM ();
491468 StatusSupport .setStatusJavaUnguarded ();
492469 if (popFrameAnchor ) {
493470 JavaFrameAnchors .popFrameAnchor ();
494471 }
495- boolean needSlowPath = ThreadingSupportImpl .needsNativeToJavaSlowpath ();
472+
473+ /* Only execute pending actions but don't do a safepoint slowpath call. */
474+ boolean needSlowPath = ActionOnTransitionToJavaSupport .isActionPending ();
496475 if (BranchProbabilityNode .probability (BranchProbabilityNode .VERY_SLOW_PATH_PROBABILITY , needSlowPath )) {
497- callSlowPathSafepointCheck ( Safepoint . ENTER_SLOW_PATH_TRANSITION_FROM_VM_TO_JAVA );
476+ callRunPendingActions ( ENTER_SLOW_PATH_RUN_PENDING_ACTIONS );
498477 }
499478 }
500479
@@ -514,16 +493,11 @@ public static void transitionVMToNative() {
514493 StatusSupport .setStatusNative ();
515494 }
516495
517- @ NodeIntrinsic (value = ForeignCallNode .class )
518- private static native void callSlowPathSafepointCheck (@ ConstantNodeParameter ForeignCallDescriptor descriptor );
519-
520496 /**
521497 * Block until I can transition from native to a new thread status. This is not inlined and need
522498 * not be fast. In fact, it often blocks. But it can not do much except block, since it starts
523499 * out running with "native" thread status.
524500 *
525- * Foreign call: {@link #ENTER_SLOW_PATH_TRANSITION_FROM_NATIVE_TO_NEW_STATUS}.
526- *
527501 * This method cannot use the {@link StubCallingConvention} with callee saved registers: the
528502 * reference map of the C call and this slow-path call must be the same. This is only guaranteed
529503 * when both the C call and the call to this slow path do not use callee saved registers.
@@ -543,27 +517,27 @@ private static void enterSlowPathTransitionFromNativeToNewStatus(int newStatus,
543517 }
544518 }
545519
546- @ NodeIntrinsic (value = ForeignCallNode .class )
547- private static native void callSlowPathNativeToNewStatus (@ ConstantNodeParameter ForeignCallDescriptor descriptor , int newThreadStatus , boolean popFrameAnchor );
548-
549520 /**
550- * Transitions from VM to Java do not need a safepoint check. We only need to make sure that any
551- * {@link ActionOnTransitionToJavaSupport pending transition action} is executed.
552- *
553- * Foreign call: {@link #ENTER_SLOW_PATH_TRANSITION_FROM_VM_TO_JAVA}.
521+ * Runs any {@link ActionOnTransitionToJavaSupport pending transition actions}.
554522 *
555523 * This method cannot use the {@link StubCallingConvention} with callee saved registers: the
556524 * reference map of the C call and this slow-path call must be the same. This is only guaranteed
557525 * when both the C call and the call to this slow path do not use callee saved registers.
558526 */
559- @ SubstrateForeignCallTarget (stubCallingConvention = false )
527+ @ SubstrateForeignCallTarget (stubCallingConvention = false , fullyUninterruptible = true )
560528 @ Uninterruptible (reason = "Must not contain safepoint checks." )
561- private static void enterSlowPathTransitionFromVMToJava () {
529+ private static void enterSlowPathRunPendingActions () {
562530 VMError .guarantee (StatusSupport .isStatusJava (), "Must be already back in Java mode" );
563-
564- slowPathRunJavaStateActions ();
531+ assert ActionOnTransitionToJavaSupport . isActionPending () : "must not be called otherwise" ;
532+ ActionOnTransitionToJavaSupport . runPendingActions ();
565533 }
566534
535+ @ NodeIntrinsic (value = ForeignCallNode .class )
536+ private static native void callRunPendingActions (@ ConstantNodeParameter ForeignCallDescriptor descriptor );
537+
538+ @ NodeIntrinsic (value = ForeignCallNode .class )
539+ private static native void callSlowPathNativeToNewStatus (@ ConstantNodeParameter ForeignCallDescriptor descriptor , int newThreadStatus , boolean popFrameAnchor );
540+
567541 /** Methods for the thread that brings the system to a safepoint. */
568542 @ AutomaticallyRegisteredImageSingleton
569543 public static final class Master {
0 commit comments