1 /*
  2  * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  */
 23 
 24 import org.testng.Assert;
 25 import org.testng.annotations.Test;
 26 
 27 import java.lang.invoke.MethodHandles;
 28 import jdk.incubator.code.OpTransformer;
 29 import jdk.incubator.code.op.CoreOp;
 30 import jdk.incubator.code.Op;
 31 import jdk.incubator.code.analysis.SSA;
 32 import jdk.incubator.code.interpreter.Interpreter;
 33 import java.lang.reflect.Method;
 34 import jdk.incubator.code.CodeReflection;
 35 import java.util.Optional;
 36 import java.util.function.IntSupplier;
 37 import java.util.stream.Stream;
 38 
 39 /*
 40  * @test
 41  * @modules jdk.incubator.code
 42  * @run testng TestSSA
 43  * @run testng/othervm -Dbabylon.ssa=cytron TestSSA
 44  */
 45 
 46 public class TestSSA {
 47 
 48     @CodeReflection
 49     static int ifelse(int a, int b, int n) {
 50         if (n < 10) {
 51             a += 1;
 52         } else {
 53             b += 2;
 54         }
 55         return a + b;
 56     }
 57 
 58     @Test
 59     public void testIfelse() throws Throwable {
 60         CoreOp.FuncOp f = getFuncOp("ifelse");
 61 
 62         CoreOp.FuncOp lf = generate(f);
 63 
 64         Assert.assertEquals((int) Interpreter.invoke(MethodHandles.lookup(), lf, 0, 0, 1), ifelse(0, 0, 1));
 65         Assert.assertEquals((int) Interpreter.invoke(MethodHandles.lookup(), lf, 0, 0, 11), ifelse(0, 0, 11));
 66     }
 67 
 68     @CodeReflection
 69     static int ifelseNested(int a, int b, int c, int d, int n) {
 70         if (n < 20) {
 71             if (n < 10) {
 72                 a += 1;
 73             } else {
 74                 b += 2;
 75             }
 76             c += 3;
 77         } else {
 78             if (n > 20) {
 79                 a += 4;
 80             } else {
 81                 b += 5;
 82             }
 83             d += 6;
 84         }
 85         return a + b + c + d;
 86     }
 87 
 88     @Test
 89     public void testIfelseNested() throws Throwable {
 90         CoreOp.FuncOp f = getFuncOp("ifelseNested");
 91 
 92         CoreOp.FuncOp lf = generate(f);
 93 
 94         for (int i : new int[]{1, 11, 20, 21}) {
 95             Assert.assertEquals((int) Interpreter.invoke(MethodHandles.lookup(), lf, 0, 0, 0, 0, i), ifelseNested(0, 0, 0, 0, i));
 96         }
 97     }
 98 
 99     @CodeReflection
100     static int loop(int n) {
101         int sum = 0;
102         for (int i = 0; i < n; i++) {
103             sum = sum + i;
104         }
105         return sum;
106     }
107 
108     @Test
109     public void testLoop() throws Throwable {
110         CoreOp.FuncOp f = getFuncOp("loop");
111 
112         CoreOp.FuncOp lf = generate(f);
113 
114         Assert.assertEquals((int) Interpreter.invoke(MethodHandles.lookup(), lf, 10), loop(10));
115     }
116 
117     @CodeReflection
118     static int nestedLoop(int n) {
119         int sum = 0;
120         for (int i = 0; i < n; i++) {
121             for (int j = 0; j < n; j++) {
122                 sum = sum + i + j;
123             }
124         }
125         return sum;
126     }
127 
128     @Test
129     public void testNestedLoop() {
130         CoreOp.FuncOp f = getFuncOp("nestedLoop");
131 
132         CoreOp.FuncOp lf = generate(f);
133 
134         Assert.assertEquals((int) Interpreter.invoke(MethodHandles.lookup(), lf, 10), nestedLoop(10));
135     }
136 
137     @CodeReflection
138     static int nestedLambdaCapture(int i) {
139         IntSupplier s = () -> {
140             int j = i + 1;
141             IntSupplier s2 = () -> i + j;
142             return s2.getAsInt() + i;
143         };
144         return s.getAsInt();
145     }
146 
147     @Test
148     public void testNestedLambdaCapture() {
149         CoreOp.FuncOp f = getFuncOp("nestedLambdaCapture");
150 
151         CoreOp.FuncOp lf = generate(f);
152 
153         Assert.assertEquals((int) Interpreter.invoke(MethodHandles.lookup(), lf, 10), nestedLambdaCapture(10));
154     }
155 
156     static CoreOp.FuncOp generate(CoreOp.FuncOp f) {
157         f.writeTo(System.out);
158 
159         CoreOp.FuncOp lf = f.transform(OpTransformer.LOWERING_TRANSFORMER);
160         lf.writeTo(System.out);
161 
162         lf = SSA.transform(lf);
163         lf.writeTo(System.out);
164         return lf;
165     }
166 
167     static CoreOp.FuncOp getFuncOp(String name) {
168         Optional<Method> om = Stream.of(TestSSA.class.getDeclaredMethods())
169                 .filter(m -> m.getName().equals(name))
170                 .findFirst();
171 
172         Method m = om.get();
173         return Op.ofMethod(m).get();
174     }
175 }