@@ -279,7 +279,7 @@ public static class Options {
279
279
* {@code gpReturnValue} as an object reference.
280
280
*/
281
281
@ Option (help = "Enables delayed deoptimization of runtime-compiled code. This slightly enlarges code metadata." )//
282
- public static final HostedOptionKey <Boolean > LazyDeoptimization = new HostedOptionKey <>(false );
282
+ public static final HostedOptionKey <Boolean > LazyDeoptimization = new HostedOptionKey <>(true );
283
283
}
284
284
285
285
/**
@@ -437,18 +437,22 @@ private void installDeoptimizedFrame(DeoptimizedFrame deoptimizedFrame) {
437
437
*/
438
438
@ NeverInline ("deoptimize must have a separate stack frame" )
439
439
public static void deoptimizeAll () {
440
- DeoptimizeAllOperation vmOp = new DeoptimizeAllOperation ();
440
+ VMOperation .guaranteeNotInProgress ("With a VM Operation in progress, we cannot determine the thread requesting deoptimization." );
441
+ DeoptimizeAllOperation vmOp = new DeoptimizeAllOperation (CurrentIsolate .getCurrentThread ());
441
442
vmOp .enqueue ();
442
443
}
443
444
444
445
private static class DeoptimizeAllOperation extends JavaVMOperation {
445
- DeoptimizeAllOperation () {
446
+ private final IsolateThread requestingThread ;
447
+
448
+ DeoptimizeAllOperation (IsolateThread requestingThread ) {
446
449
super (VMOperationInfos .get (DeoptimizeAllOperation .class , "Deoptimize all" , SystemEffect .SAFEPOINT ));
450
+ this .requestingThread = requestingThread ;
447
451
}
448
452
449
453
@ Override
450
454
protected void operate () {
451
- deoptimizeInRange (Word .zero (), Word .zero (), true );
455
+ deoptimizeInRange (Word .zero (), Word .zero (), true , requestingThread );
452
456
}
453
457
}
454
458
@@ -459,42 +463,42 @@ protected void operate() {
459
463
* @param toIp The upper address (excluding) of the method's code.
460
464
*/
461
465
@ NeverInline ("deoptimize must have a separate stack frame" )
462
- public static void deoptimizeInRange (CodePointer fromIp , CodePointer toIp , boolean deoptAll ) {
466
+ public static void deoptimizeInRange (CodePointer fromIp , CodePointer toIp , boolean deoptAll , IsolateThread requestingThread ) {
463
467
VMOperation .guaranteeInProgressAtSafepoint ("Deoptimization requires a safepoint." );
464
- deoptimizeInRangeOperation (fromIp , toIp , deoptAll );
468
+ deoptimizeInRangeOperation (fromIp , toIp , deoptAll , requestingThread );
465
469
}
466
470
467
471
/** Deoptimize a specific method on all thread stacks. */
468
472
@ NeverInline ("Starting a stack walk in the caller frame. " +
469
473
"Note that we could start the stack frame also further down the stack, because VM operation frames never need deoptimization. " +
470
474
"But we don't store stack frame information for the first frame we would need to process." )
471
- private static void deoptimizeInRangeOperation (CodePointer fromIp , CodePointer toIp , boolean deoptAll ) {
475
+ private static void deoptimizeInRangeOperation (CodePointer fromIp , CodePointer toIp , boolean deoptAll , IsolateThread requestingThread ) {
472
476
VMOperation .guaranteeInProgressAtSafepoint ("Deoptimizer.deoptimizeInRangeOperation, but not in VMOperation." );
473
477
/* Handle my own thread specially, because I do not have a JavaFrameAnchor. */
474
478
Pointer sp = KnownIntrinsics .readCallerStackPointer ();
475
479
476
- StackFrameVisitor currentThreadDeoptVisitor = getStackFrameVisitor ((Pointer ) fromIp , (Pointer ) toIp , deoptAll , CurrentIsolate .getCurrentThread ());
480
+ StackFrameVisitor currentThreadDeoptVisitor = getStackFrameVisitor ((Pointer ) fromIp , (Pointer ) toIp , deoptAll , CurrentIsolate .getCurrentThread (), requestingThread );
477
481
JavaStackWalker .walkCurrentThread (sp , currentThreadDeoptVisitor );
478
482
479
483
/* Deoptimize this method on all the other stacks. */
480
484
for (IsolateThread vmThread = VMThreads .firstThread (); vmThread .isNonNull (); vmThread = VMThreads .nextThread (vmThread )) {
481
485
if (vmThread == CurrentIsolate .getCurrentThread ()) {
482
486
continue ;
483
487
}
484
- StackFrameVisitor deoptVisitor = getStackFrameVisitor ((Pointer ) fromIp , (Pointer ) toIp , deoptAll , vmThread );
488
+ StackFrameVisitor deoptVisitor = getStackFrameVisitor ((Pointer ) fromIp , (Pointer ) toIp , deoptAll , vmThread , requestingThread );
485
489
JavaStackWalker .walkThread (vmThread , deoptVisitor );
486
490
}
487
491
maybeTestGC ();
488
492
}
489
493
490
- private static StackFrameVisitor getStackFrameVisitor (Pointer fromIp , Pointer toIp , boolean deoptAll , IsolateThread targetThread ) {
494
+ private static StackFrameVisitor getStackFrameVisitor (Pointer fromIp , Pointer toIp , boolean deoptAll , IsolateThread targetThread , IsolateThread requestingThread ) {
491
495
return new StackFrameVisitor () {
492
496
@ Override
493
497
public boolean visitRegularFrame (Pointer frameSp , CodePointer frameIp , CodeInfo codeInfo ) {
494
498
Pointer ip = (Pointer ) frameIp ;
495
499
if ((ip .aboveOrEqual (fromIp ) && ip .belowThan (toIp )) || deoptAll ) {
496
500
CodeInfoQueryResult queryResult = CodeInfoTable .lookupCodeInfoQueryResult (codeInfo , frameIp );
497
- Deoptimizer deoptimizer = new Deoptimizer (frameSp , queryResult , targetThread );
501
+ Deoptimizer deoptimizer = new Deoptimizer (frameSp , queryResult , targetThread , requestingThread );
498
502
deoptimizer .deoptSourceFrameLazily (frameIp , deoptAll );
499
503
}
500
504
return true ;
@@ -544,7 +548,8 @@ private static void deoptimizeFrame0(Pointer sp, boolean ignoreNonDeoptimizable,
544
548
return ;
545
549
}
546
550
547
- DeoptimizeFrameOperation vmOp = new DeoptimizeFrameOperation (sp , ignoreNonDeoptimizable , speculation , targetThread , deoptEagerly );
551
+ VMOperation .guaranteeNotInProgress ("With a VM Operation in progress, we cannot determine the thread requesting deoptimization." );
552
+ DeoptimizeFrameOperation vmOp = new DeoptimizeFrameOperation (sp , ignoreNonDeoptimizable , speculation , targetThread , deoptEagerly , CurrentIsolate .getCurrentThread ());
548
553
vmOp .enqueue ();
549
554
}
550
555
@@ -553,23 +558,26 @@ private static class DeoptimizeFrameOperation extends JavaVMOperation {
553
558
private final boolean ignoreNonDeoptimizable ;
554
559
private final SpeculationReason speculation ;
555
560
private final IsolateThread targetThread ;
561
+ private final IsolateThread requestingThread ;
556
562
private final boolean deoptEagerly ;
557
563
558
- DeoptimizeFrameOperation (Pointer sourceSp , boolean ignoreNonDeoptimizable , SpeculationReason speculation , IsolateThread targetThread , boolean deoptEagerly ) {
564
+ DeoptimizeFrameOperation (Pointer sourceSp , boolean ignoreNonDeoptimizable , SpeculationReason speculation , IsolateThread targetThread , boolean deoptEagerly , IsolateThread requestingThread ) {
559
565
super (VMOperationInfos .get (DeoptimizeFrameOperation .class , "Deoptimize frame" , SystemEffect .SAFEPOINT ));
560
566
this .sourceSp = sourceSp ;
561
567
this .ignoreNonDeoptimizable = ignoreNonDeoptimizable ;
562
568
this .speculation = speculation ;
563
569
this .targetThread = targetThread ;
564
570
this .deoptEagerly = deoptEagerly ;
571
+ this .requestingThread = requestingThread ;
572
+
565
573
if (Options .LazyDeoptimization .getValue () && deoptEagerly ) {
566
574
/*
567
575
* If lazy deoptimization is enabled, eager deoptimization is only used for stack
568
576
* introspection. We enforce that eager deoptimization cannot be applied to other
569
577
* threads, because we do not want an eager deoptimization operation to interrupt
570
578
* and interfere with a thread that is undergoing lazy deoptimization.
571
579
*/
572
- assert targetThread == CurrentIsolate . getCurrentThread () : "With lazy deoptimization enabled, eager deoptimization cannot be used to deoptimize other threads" ;
580
+ VMError . guarantee ( targetThread == requestingThread , "With lazy deoptimization enabled, a thread can request eager deoptimization only on itself." ) ;
573
581
}
574
582
}
575
583
@@ -587,30 +595,33 @@ protected void operate() {
587
595
uninstallLazyDeoptStubReturnAddress (sourceSp , targetThread );
588
596
ip = FrameAccess .singleton ().readReturnAddress (targetThread , sourceSp );
589
597
}
590
- deoptimizeFrame (targetThread , sourceSp , ip , ignoreNonDeoptimizable , speculation , deoptEagerly );
598
+ deoptimizeFrame (targetThread , sourceSp , ip , ignoreNonDeoptimizable , speculation , deoptEagerly , requestingThread );
591
599
}
592
600
}
593
601
594
602
@ Uninterruptible (reason = "Prevent the GC from freeing the CodeInfo object." )
595
- private static void deoptimizeFrame (IsolateThread targetThread , Pointer sp , CodePointer ip , boolean ignoreNonDeoptimizable , SpeculationReason speculation , boolean deoptEagerly ) {
603
+ private static void deoptimizeFrame (IsolateThread targetThread , Pointer sp , CodePointer ip , boolean ignoreNonDeoptimizable , SpeculationReason speculation , boolean deoptEagerly ,
604
+ IsolateThread requestingThread ) {
596
605
UntetheredCodeInfo untetheredInfo = CodeInfoTable .lookupCodeInfo (ip );
597
606
Object tether = CodeInfoAccess .acquireTether (untetheredInfo );
598
607
try {
599
608
CodeInfo info = CodeInfoAccess .convert (untetheredInfo , tether );
600
- deoptimize (targetThread , sp , ip , ignoreNonDeoptimizable , speculation , info , deoptEagerly );
609
+ deoptimize (targetThread , sp , ip , ignoreNonDeoptimizable , speculation , info , deoptEagerly , requestingThread );
601
610
} finally {
602
611
CodeInfoAccess .releaseTether (untetheredInfo , tether );
603
612
}
604
613
}
605
614
606
615
@ Uninterruptible (reason = "Pass the now protected CodeInfo object to interruptible code." , calleeMustBe = false )
607
- private static void deoptimize (IsolateThread targetThread , Pointer sp , CodePointer ip , boolean ignoreNonDeoptimizable , SpeculationReason speculation , CodeInfo info , boolean deoptEagerly ) {
608
- deoptimize0 (targetThread , sp , ip , ignoreNonDeoptimizable , speculation , info , deoptEagerly );
616
+ private static void deoptimize (IsolateThread targetThread , Pointer sp , CodePointer ip , boolean ignoreNonDeoptimizable , SpeculationReason speculation , CodeInfo info , boolean deoptEagerly ,
617
+ IsolateThread requestingThread ) {
618
+ deoptimize0 (targetThread , sp , ip , ignoreNonDeoptimizable , speculation , info , deoptEagerly , requestingThread );
609
619
}
610
620
611
- private static void deoptimize0 (IsolateThread targetThread , Pointer sp , CodePointer ip , boolean ignoreNonDeoptimizable , SpeculationReason speculation , CodeInfo info , boolean deoptEagerly ) {
621
+ private static void deoptimize0 (IsolateThread targetThread , Pointer sp , CodePointer ip , boolean ignoreNonDeoptimizable , SpeculationReason speculation , CodeInfo info , boolean deoptEagerly ,
622
+ IsolateThread requestingThread ) {
612
623
CodeInfoQueryResult queryResult = CodeInfoTable .lookupCodeInfoQueryResult (info , ip );
613
- Deoptimizer deoptimizer = new Deoptimizer (sp , queryResult , targetThread );
624
+ Deoptimizer deoptimizer = new Deoptimizer (sp , queryResult , targetThread , requestingThread );
614
625
if (deoptEagerly ) {
615
626
DeoptimizedFrame sourceFrame = deoptimizer .deoptSourceFrameEagerly (ip , ignoreNonDeoptimizable );
616
627
if (sourceFrame != null ) {
@@ -687,11 +698,13 @@ private static void registerSpeculationFailure(SubstrateInstalledCode installedC
687
698
protected int targetContentSize ;
688
699
689
700
private final DeoptState deoptState ;
701
+ private final IsolateThread requestingThread ;
690
702
691
- public Deoptimizer (Pointer sourceSp , CodeInfoQueryResult sourceChunk , IsolateThread targetThread ) {
703
+ public Deoptimizer (Pointer sourceSp , CodeInfoQueryResult sourceChunk , IsolateThread targetThread , IsolateThread requestingThread ) {
692
704
VMError .guarantee (sourceChunk != null , "Must not be null." );
693
705
this .sourceChunk = sourceChunk ;
694
706
this .deoptState = new DeoptState (sourceSp , targetThread );
707
+ this .requestingThread = requestingThread ;
695
708
}
696
709
697
710
public DeoptState getDeoptState () {
@@ -889,7 +902,7 @@ private static DeoptimizedFrame constructLazilyDeoptimizedFrameInterruptibly0(Po
889
902
maybeTestGC ();
890
903
CodeInfoQueryResult sourceChunk = CodeInfoTable .lookupCodeInfoQueryResult (info , ip );
891
904
maybeTestGC ();
892
- Deoptimizer deoptimizer = new Deoptimizer (sourceSp , sourceChunk , CurrentIsolate .getCurrentThread ());
905
+ Deoptimizer deoptimizer = new Deoptimizer (sourceSp , sourceChunk , CurrentIsolate .getCurrentThread (), CurrentIsolate . getCurrentThread () );
893
906
maybeTestEagerDeoptInLazyDeoptFatalError (deoptimizer , ip );
894
907
DeoptimizedFrame deoptFrame = deoptimizer .doDeoptSourceFrame (ip , true , false );
895
908
if (hasException ) {
@@ -1021,17 +1034,14 @@ static int savedBasePointerSize() {
1021
1034
*
1022
1035
* @param pc A code address inside the source method (= the method to deoptimize)
1023
1036
*/
1024
- public void deoptSourceFrameLazily (CodePointer pc , boolean ignoreNonDeoptimizable ) {
1037
+ private void deoptSourceFrameLazily (CodePointer pc , boolean ignoreNonDeoptimizable ) {
1025
1038
assert VMOperation .isInProgressAtSafepoint ();
1026
1039
if (!Options .LazyDeoptimization .getValue ()) {
1027
1040
deoptSourceFrameEagerly (pc , ignoreNonDeoptimizable );
1028
1041
return ;
1029
1042
}
1030
- if (checkLazyDeoptimized (deoptState .targetThread , deoptState .sourceSp )) {
1031
- // already lazily deoptimized, nothing to do
1032
- return ;
1033
- } else if (checkEagerDeoptimized (deoptState .targetThread , deoptState .sourceSp ) != null ) {
1034
- // if already eagerly deoptimized, don't lazily deoptimize.
1043
+ if (checkLazyDeoptimized (deoptState .targetThread , deoptState .sourceSp ) || checkEagerDeoptimized (deoptState .targetThread , deoptState .sourceSp ) != null ) {
1044
+ // already deoptimized, nothing to do
1035
1045
return ;
1036
1046
}
1037
1047
@@ -1051,7 +1061,7 @@ public void deoptSourceFrameLazily(CodePointer pc, boolean ignoreNonDeoptimizabl
1051
1061
/**
1052
1062
* Deoptimizes a source frame eagerly.
1053
1063
*/
1054
- public DeoptimizedFrame deoptSourceFrameEagerly (CodePointer pc , boolean ignoreNonDeoptimizable ) {
1064
+ private DeoptimizedFrame deoptSourceFrameEagerly (CodePointer pc , boolean ignoreNonDeoptimizable ) {
1055
1065
if (!canBeDeoptimized (sourceChunk .getFrameInfo ())) {
1056
1066
if (ignoreNonDeoptimizable ) {
1057
1067
return null ;
@@ -1065,6 +1075,11 @@ public DeoptimizedFrame deoptSourceFrameEagerly(CodePointer pc, boolean ignoreNo
1065
1075
return operation .getResult ();
1066
1076
}
1067
1077
1078
+ public DeoptimizedFrame deoptimizeEagerly () {
1079
+ VMError .guarantee (requestingThread == CurrentIsolate .getCurrentThread (), "This method should be called by the thread which creates the Deoptimizer." );
1080
+ return deoptSourceFrameEagerly (sourceChunk .getIP (), false );
1081
+ }
1082
+
1068
1083
@ Uninterruptible (reason = "Prevent stack walks from seeing an inconsistent stack." )
1069
1084
private static void installLazyDeoptStubReturnAddress (boolean returnValueIsObject , Pointer sourceSp , IsolateThread targetThread ) {
1070
1085
assert Options .LazyDeoptimization .getValue ();
@@ -1112,7 +1127,7 @@ private static final class EagerDeoptSourceFrameOperation extends JavaVMOperatio
1112
1127
this .ignoreNonDeoptimizable = ignoreNonDeoptimizable ;
1113
1128
this .result = null ;
1114
1129
if (Options .LazyDeoptimization .getValue ()) {
1115
- assert receiver .deoptState .targetThread == CurrentIsolate . getCurrentThread () : "With lazy deoptimization enabled, eager deoptimization cannot be used to deoptimize other threads" ;
1130
+ VMError . guarantee ( receiver .deoptState .targetThread == receiver . requestingThread , "With lazy deoptimization enabled, a thread can request eager deoptimization only on itself." ) ;
1116
1131
}
1117
1132
}
1118
1133
@@ -1144,9 +1159,10 @@ private static boolean canBeDeoptimized(FrameInfoQueryResult frame) {
1144
1159
}
1145
1160
1146
1161
private DeoptimizedFrame doDeoptSourceFrame (CodePointer pc , boolean ignoreNonDeoptimizable , boolean isEagerDeopt ) {
1147
- assert !Options .LazyDeoptimization .getValue () ||
1148
- deoptState .targetThread == CurrentIsolate .getCurrentThread () : "with lazy deoptimization, this method may only be called for the current thread" ;
1149
1162
assert !isEagerDeopt || VMOperation .isInProgressAtSafepoint () : "eager deopts may only happen at a safepoint" ;
1163
+ if (Options .LazyDeoptimization .getValue ()) {
1164
+ VMError .guarantee (deoptState .targetThread == requestingThread , "With lazy deoptimization enabled, this method may only be called for the requesting thread." );
1165
+ }
1150
1166
1151
1167
DeoptimizedFrame existing = checkEagerDeoptimized (deoptState .targetThread , deoptState .sourceSp );
1152
1168
if (existing != null ) {
0 commit comments