@@ -3749,6 +3749,130 @@ private static boolean isPcSkippableNoOp(Instruction instruction) {
37493749 * label is purely decorative and a preceding ``pc = i; break;``
37503750 * may be omitted.
37513751 */
3752+ /**
3753+ * A basic block: a maximal straight-line instruction range [start, end) with
3754+ * a single entry (start) and successor block indices. Foundation for the
3755+ * structured-control-flow (relooper) emitter that will replace the switch(pc)
3756+ * state machine with if/else/while for reducible CFGs (keeping the generator
3757+ * model). Pure analysis -- nothing consumes it for emission yet.
3758+ */
3759+ static final class BasicBlock {
3760+ final int start ;
3761+ int end ;
3762+ final java .util .List <Integer > succs = new java .util .ArrayList <Integer >();
3763+ BasicBlock (int start ) { this .start = start ; }
3764+ }
3765+
3766+ /**
3767+ * Partition a method's instruction list into basic blocks and wire successor
3768+ * edges. Leaders: index 0, every branch/switch target, the instruction after a
3769+ * branch/return/throw, and try/catch range + handler boundaries.
3770+ */
3771+ static java .util .List <BasicBlock > buildBasicBlocks (List <Instruction > instructions , Map <Label , Integer > labelToIndex ) {
3772+ int n = instructions .size ();
3773+ boolean [] leader = new boolean [n + 1 ];
3774+ if (n > 0 ) {
3775+ leader [0 ] = true ;
3776+ }
3777+ for (int i = 0 ; i < n ; i ++) {
3778+ Instruction instr = instructions .get (i );
3779+ if (instr instanceof Jump ) {
3780+ Integer t = labelToIndex .get (((Jump ) instr ).getLabel ());
3781+ if (t != null && t < n ) {
3782+ leader [t ] = true ;
3783+ }
3784+ if (i + 1 < n ) {
3785+ leader [i + 1 ] = true ;
3786+ }
3787+ } else if (instr instanceof SwitchInstruction ) {
3788+ SwitchInstruction sw = (SwitchInstruction ) instr ;
3789+ if (sw .getDefaultLabel () != null ) {
3790+ Integer d = labelToIndex .get (sw .getDefaultLabel ());
3791+ if (d != null && d < n ) { leader [d ] = true ; }
3792+ }
3793+ if (sw .getLabels () != null ) {
3794+ for (Label l : sw .getLabels ()) {
3795+ Integer d = l == null ? null : labelToIndex .get (l );
3796+ if (d != null && d < n ) { leader [d ] = true ; }
3797+ }
3798+ }
3799+ if (i + 1 < n ) { leader [i + 1 ] = true ; }
3800+ } else if (instr instanceof TryCatch ) {
3801+ TryCatch tc = (TryCatch ) instr ;
3802+ for (Label l : new Label []{ tc .getStart (), tc .getEnd (), tc .getHandler () }) {
3803+ Integer d = l == null ? null : labelToIndex .get (l );
3804+ if (d != null && d < n ) { leader [d ] = true ; }
3805+ }
3806+ } else if (isTerminatingInstruction (instr ) && i + 1 < n ) {
3807+ leader [i + 1 ] = true ;
3808+ }
3809+ }
3810+
3811+ java .util .List <BasicBlock > blocks = new java .util .ArrayList <BasicBlock >();
3812+ java .util .Map <Integer , Integer > startToBlock = new java .util .HashMap <Integer , Integer >();
3813+ BasicBlock cur = null ;
3814+ for (int i = 0 ; i < n ; i ++) {
3815+ if (leader [i ] || cur == null ) {
3816+ if (cur != null ) { cur .end = i ; }
3817+ cur = new BasicBlock (i );
3818+ startToBlock .put (i , blocks .size ());
3819+ blocks .add (cur );
3820+ }
3821+ }
3822+ if (cur != null ) { cur .end = n ; }
3823+
3824+ for (BasicBlock b : blocks ) {
3825+ Instruction last = b .end > b .start ? instructions .get (b .end - 1 ) : null ;
3826+ boolean addFallThrough = true ;
3827+ if (last instanceof Jump ) {
3828+ Integer t = labelToIndex .get (((Jump ) last ).getLabel ());
3829+ if (t != null && startToBlock .containsKey ((int ) t )) {
3830+ b .succs .add (startToBlock .get ((int ) t ));
3831+ }
3832+ if (last .getOpcode () == Opcodes .GOTO ) {
3833+ addFallThrough = false ;
3834+ }
3835+ } else if (last instanceof SwitchInstruction ) {
3836+ SwitchInstruction sw = (SwitchInstruction ) last ;
3837+ if (sw .getDefaultLabel () != null ) {
3838+ Integer d = labelToIndex .get (sw .getDefaultLabel ());
3839+ if (d != null && startToBlock .containsKey ((int ) d )) { b .succs .add (startToBlock .get ((int ) d )); }
3840+ }
3841+ if (sw .getLabels () != null ) {
3842+ for (Label l : sw .getLabels ()) {
3843+ Integer d = l == null ? null : labelToIndex .get (l );
3844+ if (d != null && startToBlock .containsKey ((int ) d )) { b .succs .add (startToBlock .get ((int ) d )); }
3845+ }
3846+ }
3847+ addFallThrough = false ;
3848+ } else if (last != null && isTerminatingInstruction (last )) {
3849+ addFallThrough = false ;
3850+ }
3851+ if (addFallThrough && startToBlock .containsKey (b .end )) {
3852+ b .succs .add (startToBlock .get (b .end ));
3853+ }
3854+ }
3855+ return blocks ;
3856+ }
3857+
3858+ /**
3859+ * Conservatively true when the block graph is acyclic in index order (no back
3860+ * edge: every successor block index is strictly greater than its source).
3861+ * Acyclic single-entry blocks are the slice the structured emitter handles
3862+ * first (if / if-else); methods with loops or any backward edge stay on
3863+ * switch(pc).
3864+ */
3865+ static boolean isAcyclicForward (java .util .List <BasicBlock > blocks ) {
3866+ for (int i = 0 ; i < blocks .size (); i ++) {
3867+ for (int s : blocks .get (i ).succs ) {
3868+ if (s <= i ) {
3869+ return false ;
3870+ }
3871+ }
3872+ }
3873+ return true ;
3874+ }
3875+
37523876 private static java .util .Set <Integer > computeJumpTargets (List <Instruction > instructions , Map <Label , Integer > labelToIndex ,
37533877 boolean forceThrowingTargets ) {
37543878 java .util .Set <Integer > targets = new java .util .HashSet <Integer >();
0 commit comments