@@ -864,17 +864,24 @@ protected static final class Target {
864
864
final FixedNode entry ;
865
865
final FixedNode originalEntry ;
866
866
final FrameStateBuilder state ;
867
+ final boolean reachable ;
867
868
868
869
public Target (FixedNode entry , FrameStateBuilder state ) {
870
+ this (entry , state , null );
871
+ }
872
+
873
+ public Target (FixedNode entry , FrameStateBuilder state , FixedNode originalEntry ) {
869
874
this .entry = entry ;
870
875
this .state = state ;
871
- this .originalEntry = null ;
876
+ this .originalEntry = originalEntry ;
877
+ this .reachable = true ;
872
878
}
873
879
874
- public Target (FixedNode entry , FrameStateBuilder state , FixedNode originalEntry ) {
880
+ public Target (FixedNode entry , FrameStateBuilder state , FixedNode originalEntry , boolean reachable ) {
875
881
this .entry = entry ;
876
882
this .state = state ;
877
883
this .originalEntry = originalEntry ;
884
+ this .reachable = reachable ;
878
885
}
879
886
880
887
public FixedNode getEntry () {
@@ -888,6 +895,15 @@ public FixedNode getOriginalEntry() {
888
895
public FrameStateBuilder getState () {
889
896
return state ;
890
897
}
898
+
899
+ /**
900
+ * Indicates whether the target block is actually reachable. If not, {@link #getEntry()}
901
+ * will lead to a dead end (e.g., exception). Thus, no ends must be added to the target
902
+ * block's merge.
903
+ */
904
+ public boolean isReachable () {
905
+ return reachable ;
906
+ }
891
907
}
892
908
893
909
@ SuppressWarnings ("serial" )
@@ -3438,6 +3454,13 @@ private FixedNode createTarget(BciBlock block, FrameStateBuilder state, boolean
3438
3454
} else {
3439
3455
setFirstInstruction (block , graph .add (new BeginNode ()));
3440
3456
}
3457
+ /*
3458
+ * The target is the block's first instruction which may be preceded by exits of
3459
+ * loops or exception handling that must be done before the jump. The target.entry
3460
+ * holds the start of this sequence of operations. As the block is seen the first
3461
+ * time as jump target, we cannot check for unstructured locking, as this requires
3462
+ * to compare the lock stacks of two framestates to be merged.
3463
+ */
3441
3464
Target target = checkLoopExit (checkUnwind (getFirstInstruction (block ), block , state ), block );
3442
3465
FixedNode result = target .entry ;
3443
3466
FrameStateBuilder currentEntryState = target .state == state ? (canReuseState ? state : state .copy ()) : target .state ;
@@ -3461,6 +3484,11 @@ private FixedNode createTarget(BciBlock block, FrameStateBuilder state, boolean
3461
3484
// location instead of the destination.
3462
3485
loopEnd = graph .add (new LoopEndNode (loopBegin ));
3463
3486
}
3487
+ /*
3488
+ * The target is created from the loopEnd which may be preceded by exits of loops or
3489
+ * exception handling that must be done before the jump. The target.entry holds the
3490
+ * start of this sequence of operations.
3491
+ */
3464
3492
Target target = checkUnstructuredLocking (checkLoopExit (new Target (loopEnd , state .copy ()), block ), block , getEntryState (block ));
3465
3493
FixedNode result = target .entry ;
3466
3494
/*
@@ -3471,15 +3499,30 @@ private FixedNode createTarget(BciBlock block, FrameStateBuilder state, boolean
3471
3499
assert !(block instanceof ExceptionDispatchBlock ) : block ;
3472
3500
assert !getEntryState (block ).rethrowException ();
3473
3501
target .state .setRethrowException (false );
3474
- getEntryState (block ).merge (loopBegin , target .state );
3475
- debug .log ("createTarget %s: merging backward branch to loop header %s, result: %s" , block , loopBegin , result );
3502
+
3503
+ if (target .isReachable ()) {
3504
+ getEntryState (block ).merge (loopBegin , target .state );
3505
+ debug .log ("createTarget %s: merging backward branch to loop header %s, result: %s" , block , loopBegin , result );
3506
+ } else {
3507
+ debug .log ("createTarget %s: Unreachable target. This could be due to an exception being thrown (e.g., unstructured locking)." , block );
3508
+ }
3476
3509
3477
3510
return result ;
3478
3511
}
3479
3512
assert currentBlock == null || currentBlock .getId () < block .getId () : "must not be backward branch" ;
3480
3513
assert getFirstInstruction (block ).next () == null : "bytecodes already parsed for block" ;
3481
3514
3482
- if (getFirstInstruction (block ) instanceof AbstractBeginNode && !(getFirstInstruction (block ) instanceof AbstractMergeNode )) {
3515
+ // The EndNode for the new edge to merge.
3516
+ EndNode newEnd = graph .add (new EndNode ());
3517
+ /*
3518
+ * The target is created from the newEnd which may be preceded by exits of loops or
3519
+ * exception handling that must be done before the jump. The target.entry holds the
3520
+ * start of this sequence of operations.
3521
+ */
3522
+ Target target = checkUnstructuredLocking (checkLoopExit (checkUnwind (newEnd , block , state ), block ), block , getEntryState (block ));
3523
+ FixedNode result = target .entry ;
3524
+
3525
+ if (target .isReachable () && getFirstInstruction (block ) instanceof AbstractBeginNode && !(getFirstInstruction (block ) instanceof AbstractMergeNode )) {
3483
3526
/*
3484
3527
* This is the second time we see this block. Create the actual MergeNode and the
3485
3528
* End Node for the already existing edge.
@@ -3505,15 +3548,14 @@ private FixedNode createTarget(BciBlock block, FrameStateBuilder state, boolean
3505
3548
setFirstInstruction (block , mergeNode );
3506
3549
}
3507
3550
3508
- AbstractMergeNode mergeNode = (AbstractMergeNode ) getFirstInstruction (block );
3509
-
3510
- // The EndNode for the newly merged edge.
3511
- EndNode newEnd = graph .add (new EndNode ());
3512
- Target target = checkUnstructuredLocking (checkLoopExit (checkUnwind (newEnd , block , state ), block ), block , getEntryState (block ));
3513
- FixedNode result = target .entry ;
3514
- getEntryState (block ).merge (mergeNode , target .state );
3515
- mergeNode .addForwardEnd (newEnd );
3516
- debug .log ("createTarget %s: merging state, result: %s" , block , result );
3551
+ if (target .isReachable ()) {
3552
+ AbstractMergeNode mergeNode = (AbstractMergeNode ) getFirstInstruction (block );
3553
+ getEntryState (block ).merge (mergeNode , target .state );
3554
+ mergeNode .addForwardEnd (newEnd );
3555
+ debug .log ("createTarget %s: merging state, result: %s" , block , result );
3556
+ } else {
3557
+ debug .log ("createTarget %s: Unreachable target. This could be due to an exception being thrown (e.g., unstructured locking)." , block );
3558
+ }
3517
3559
3518
3560
return result ;
3519
3561
}
0 commit comments