@@ -203,7 +203,7 @@ public Block.Builder lower(Block.Builder b, OpTransformer opT) {
203
203
}
204
204
205
205
/**
206
- * The break operation, that can model Java language continue statements with label identifiers.
206
+ * The continue operation, that can model Java language continue statements with label identifiers.
207
207
*/
208
208
@ OpFactory .OpDeclaration (JavaContinueOp .NAME )
209
209
public static final class JavaContinueOp extends JavaLabelOp {
@@ -237,29 +237,28 @@ record BranchTarget(Block.Builder breakBlock, Block.Builder continueBlock) {
237
237
238
238
static final String BRANCH_TARGET_MAP_PROPERTY_KEY = "BRANCH_TARGET_MAP" ;
239
239
240
- static BranchTarget getBranchTarget (CopyContext cc , Op op ) {
240
+ static BranchTarget getBranchTarget (CopyContext cc , CodeElement <?, ?> codeElement ) {
241
241
@ SuppressWarnings ("unchecked" )
242
- Map <Op , BranchTarget > m = (Map <Op , BranchTarget >) cc .getProperty (BRANCH_TARGET_MAP_PROPERTY_KEY );
242
+ Map <CodeElement <?, ?>, BranchTarget > m = (Map <CodeElement <?, ?> , BranchTarget >) cc .getProperty (BRANCH_TARGET_MAP_PROPERTY_KEY );
243
243
if (m != null ) {
244
- return m .get (op );
244
+ return m .get (codeElement );
245
245
}
246
-
247
246
return null ;
248
247
}
249
248
250
- static void setBranchTarget (CopyContext cc , Op label , BranchTarget t ) {
249
+ static void setBranchTarget (CopyContext cc , CodeElement <?, ?> codeElement , BranchTarget t ) {
251
250
@ SuppressWarnings ("unchecked" )
252
- Map <Op , BranchTarget > x = (Map <Op , BranchTarget >) cc .computePropertyIfAbsent (
251
+ Map <CodeElement <?, ?>, BranchTarget > x = (Map <CodeElement <?, ?> , BranchTarget >) cc .computePropertyIfAbsent (
253
252
BRANCH_TARGET_MAP_PROPERTY_KEY , k -> new HashMap <>());
254
- x .put (label , t );
253
+ x .put (codeElement , t );
255
254
}
256
255
257
256
/**
258
257
* The yield operation, that can model Java language yield statements.
259
258
*/
260
259
@ OpFactory .OpDeclaration (JavaYieldOp .NAME )
261
260
public static final class JavaYieldOp extends ExtendedOp
262
- implements Op .BodyTerminating , JavaStatement {
261
+ implements Op .BodyTerminating , JavaStatement , Op . Lowerable {
263
262
public static final String NAME = "java.yield" ;
264
263
265
264
public JavaYieldOp (ExternalizedOp def ) {
@@ -297,6 +296,40 @@ public Value yieldValue() {
297
296
public TypeElement resultType () {
298
297
return VOID ;
299
298
}
299
+
300
+ @ Override
301
+ public Block .Builder lower (Block .Builder b , OpTransformer opT ) {
302
+ // for now, we will use breakBlock field to indicate java.yield target block
303
+ return lower (b , BranchTarget ::breakBlock );
304
+ }
305
+
306
+ Block .Builder lower (Block .Builder b , Function <BranchTarget , Block .Builder > f ) {
307
+ Op opt = target ();
308
+ BranchTarget t = getBranchTarget (b .context (), opt );
309
+ if (t != null ) {
310
+ b .op (branch (f .apply (t ).successor (b .context ().getValue (yieldValue ()))));
311
+ } else {
312
+ throw new IllegalStateException ("No branch target for operation: " + opt );
313
+ }
314
+ return b ;
315
+ }
316
+
317
+ Op target () {
318
+ return innerMostEnclosingTarget ();
319
+ }
320
+
321
+ Op innerMostEnclosingTarget () {
322
+ Op op = this ;
323
+ Body b ;
324
+ do {
325
+ b = op .ancestorBody ();
326
+ op = b .parentOp ();
327
+ if (op == null ) {
328
+ throw new IllegalStateException ("No enclosing switch" );
329
+ }
330
+ } while (!(op instanceof JavaSwitchExpressionOp ));
331
+ return op ;
332
+ }
300
333
}
301
334
302
335
/**
@@ -757,13 +790,119 @@ public List<Body> bodies() {
757
790
}
758
791
759
792
@ Override
760
- public Block .Builder lower (Block .Builder b , OpTransformer opT ) {
761
- throw new UnsupportedOperationException ();
793
+ public TypeElement resultType () {
794
+ return resultType ;
795
+ }
796
+
797
+ private boolean haveNullCase () {
798
+ /*
799
+ case null is modeled like this:
800
+ (%4 : T)boolean -> {
801
+ %5 : java.lang.Object = constant @null;
802
+ %6 : boolean = invoke %4 %5 @"java.util.Objects::equals(java.lang.Object, java.lang.Object)boolean";
803
+ yield %6;
804
+ }
805
+ * */
806
+ for (int i = 0 ; i < bodies ().size () - 2 ; i +=2 ) {
807
+ Body labelBody = bodies ().get (i );
808
+ if (labelBody .blocks ().size () != 1 ) {
809
+ continue ; // we skip, for now
810
+ }
811
+ Op terminatingOp = bodies ().get (i ).entryBlock ().terminatingOp ();
812
+ //@@@ when op pattern matching is ready, we can use it
813
+ if (terminatingOp instanceof YieldOp yieldOp &&
814
+ yieldOp .yieldValue () instanceof Op .Result opr &&
815
+ opr .op () instanceof InvokeOp invokeOp &&
816
+ invokeOp .invokeDescriptor ().equals (MethodRef .method (Objects .class , "equals" , boolean .class , Object .class , Object .class )) &&
817
+ invokeOp .operands ().stream ().anyMatch (o -> o instanceof Op .Result r && r .op () instanceof ConstantOp cop && cop .value () == null )) {
818
+ return true ;
819
+ }
820
+ }
821
+ return false ;
762
822
}
763
823
764
824
@ Override
765
- public TypeElement resultType () {
766
- return resultType ;
825
+ public Block .Builder lower (Block .Builder b , OpTransformer opT ) {
826
+
827
+ Value selectorExpression = b .context ().getValue (operands ().get (0 ));
828
+
829
+ if (!haveNullCase ()) {
830
+ Block .Builder throwBlock = b .block ();
831
+ throwBlock .op (_throw (
832
+ throwBlock .op (_new (FunctionType .functionType (JavaType .type (NullPointerException .class ))))
833
+ ));
834
+
835
+ Block .Builder continueBlock = b .block ();
836
+
837
+ Result p = b .op (invoke (MethodRef .method (Objects .class , "equals" , boolean .class , Object .class , Object .class ),
838
+ selectorExpression , b .op (constant (J_L_OBJECT , null ))));
839
+ b .op (conditionalBranch (p , throwBlock .successor (), continueBlock .successor ()));
840
+
841
+ b = continueBlock ;
842
+ }
843
+
844
+ List <Block .Builder > blocks = new ArrayList <>();
845
+ for (int i = 0 ; i < bodies ().size (); i ++) {
846
+ Block .Builder bb = b .block ();
847
+ if (i == 0 ) {
848
+ bb = b ;
849
+ }
850
+ blocks .add (bb );
851
+ }
852
+
853
+ Block .Builder exit ;
854
+ if (bodies ().isEmpty ()) {
855
+ exit = b ;
856
+ } else {
857
+ exit = b .block (resultType ());
858
+ exit .context ().mapValue (result (), exit .parameters ().get (0 ));
859
+ }
860
+
861
+ setBranchTarget (b .context (), this , new BranchTarget (exit , null ));
862
+ // map expr body to nextExprBlock
863
+ // this mapping will be used for lowering SwitchFallThroughOp
864
+ for (int i = 1 ; i < bodies ().size () - 2 ; i +=2 ) {
865
+ setBranchTarget (b .context (), bodies ().get (i ), new BranchTarget (null , blocks .get (i + 2 )));
866
+ }
867
+
868
+ for (int i = 0 ; i < bodies ().size (); i ++) {
869
+ boolean isLabelBody = i % 2 == 0 ;
870
+ Block .Builder curr = blocks .get (i );
871
+ if (isLabelBody ) {
872
+ Block .Builder expression = blocks .get (i + 1 );
873
+ boolean isDefaultLabel = i == blocks .size () - 2 ;
874
+ Block .Builder nextLabel = isDefaultLabel ? null : blocks .get (i + 2 );
875
+ curr .transformBody (bodies ().get (i ), List .of (selectorExpression ), opT .andThen ((block , op ) -> {
876
+ switch (op ) {
877
+ case YieldOp yop -> {
878
+ if (isDefaultLabel ) {
879
+ block .op (branch (expression .successor ()));
880
+ } else {
881
+ block .op (conditionalBranch (
882
+ block .context ().getValue (yop .yieldValue ()),
883
+ expression .successor (),
884
+ nextLabel .successor ()
885
+ ));
886
+ }
887
+ }
888
+ case Lowerable lop -> block = lop .lower (block );
889
+ default -> block .op (op );
890
+ }
891
+ return block ;
892
+ }));
893
+ } else { // expression body
894
+ curr .transformBody (bodies ().get (i ), blocks .get (i ).parameters (), opT .andThen ((block , op ) -> {
895
+ switch (op ) {
896
+ case YieldOp yop -> block .op (branch (exit .successor (block .context ().getValue (yop .yieldValue ()))));
897
+ case Lowerable lop -> block = lop .lower (block );
898
+ default -> block .op (op );
899
+ }
900
+ return block ;
901
+ }));
902
+ }
903
+ }
904
+
905
+ return exit ;
767
906
}
768
907
}
769
908
@@ -773,7 +912,7 @@ public TypeElement resultType() {
773
912
*/
774
913
@ OpFactory .OpDeclaration (JavaSwitchFallthroughOp .NAME )
775
914
public static final class JavaSwitchFallthroughOp extends ExtendedOp
776
- implements Op .BodyTerminating {
915
+ implements Op .BodyTerminating , Op . Lowerable {
777
916
public static final String NAME = "java.switch.fallthrough" ;
778
917
779
918
public JavaSwitchFallthroughOp (ExternalizedOp def ) {
@@ -797,6 +936,21 @@ public JavaSwitchFallthroughOp transform(CopyContext cc, OpTransformer ot) {
797
936
public TypeElement resultType () {
798
937
return VOID ;
799
938
}
939
+
940
+ @ Override
941
+ public Block .Builder lower (Block .Builder b , OpTransformer opT ) {
942
+ return lower (b , BranchTarget ::continueBlock );
943
+ }
944
+
945
+ Block .Builder lower (Block .Builder b , Function <BranchTarget , Block .Builder > f ) {
946
+ BranchTarget t = getBranchTarget (b .context (), parentBlock ().parentBody ());
947
+ if (t != null ) {
948
+ b .op (branch (f .apply (t ).successor ()));
949
+ } else {
950
+ throw new IllegalStateException ("No branch target for operation: " + this );
951
+ }
952
+ return b ;
953
+ }
800
954
}
801
955
802
956
/**
0 commit comments