1 import org.testng.Assert; 2 import org.testng.annotations.Test; 3 4 import java.lang.invoke.MethodHandles; 5 import java.lang.reflect.Method; 6 import jdk.incubator.code.*; 7 import jdk.incubator.code.analysis.SSA; 8 import jdk.incubator.code.interpreter.Interpreter; 9 import jdk.incubator.code.CodeReflection; 10 import java.util.Optional; 11 import java.util.function.Predicate; 12 import java.util.stream.Stream; 13 14 import static jdk.incubator.code.dialect.core.CoreOp.FuncOp; 15 import static jdk.incubator.code.dialect.core.CoreOp.VarAccessOp.VarLoadOp; 16 import static jdk.incubator.code.dialect.core.CoreOp.VarAccessOp.VarStoreOp; 17 import static jdk.incubator.code.dialect.core.CoreOp.VarOp; 18 19 /* 20 * @test 21 * @modules jdk.incubator.code 22 * @run testng TestRemoveFinalVars 23 */ 24 25 public class TestRemoveFinalVars { 26 27 @CodeReflection 28 static boolean f() { 29 final int x = 8; // final var 30 int y = x + 2; // final var 31 int z = y + 3; // non final var 32 z++; 33 return x == 8 && y == 10 && z == 14; 34 } 35 36 @Test 37 void test() { 38 FuncOp f = getFuncOp(this.getClass(),"f"); 39 System.out.println(f.toText()); 40 FuncOp lf = lower(f); 41 System.out.println(lf.toText()); 42 43 FuncOp f2 = f.transform(TestRemoveFinalVars::rmFinalVars); 44 System.out.println(f2.toText()); 45 FuncOp lf2 = lower(f2); 46 System.out.println(lf2.toText()); 47 48 Assert.assertEquals(Interpreter.invoke(MethodHandles.lookup(), lf), Interpreter.invoke(MethodHandles.lookup(), lf2)); 49 50 Op op = SSA.transform(lower(f)); 51 System.out.println(op.toText()); 52 } 53 54 static FuncOp lower(FuncOp funcOp) { 55 return funcOp.transform(OpTransformer.LOWERING_TRANSFORMER); 56 } 57 58 static Block.Builder rmFinalVars(Block.Builder block, Op op) { 59 if (op instanceof VarOp varOp) { 60 // Is the variable stored to? If not we can remove it 61 // otherwise, it's not considered final and we copy it 62 if (isValueUsedWithOp(varOp.result(), o -> o instanceof VarStoreOp)) { 63 block.op(varOp); 64 } 65 } else if (op instanceof VarLoadOp varLoadOp) { 66 // If the variable is not stored to 67 if (!isValueUsedWithOp(varLoadOp.varOp().result(), o -> o instanceof VarStoreOp)) { 68 // Map result of load from variable to the value that initialized the variable 69 // Subsequently encountered input operations using the result will be copied 70 // to output operations using the mapped value 71 CopyContext cc = block.context(); 72 cc.mapValue(varLoadOp.result(), cc.getValue(varLoadOp.varOp().operands().get(0))); 73 } else { 74 block.op(varLoadOp); 75 } 76 } else { 77 block.op(op); 78 } 79 return block; 80 } 81 82 private static boolean isValueUsedWithOp(Value value, Predicate<Op> opPredicate) { 83 for (Op.Result user : value.uses()) { 84 if (opPredicate.test(user.op())) { 85 return true; 86 } 87 } 88 return false; 89 } 90 91 static FuncOp getFuncOp(Class<?> c, String name) { 92 Optional<Method> om = Stream.of(c.getDeclaredMethods()) 93 .filter(m -> m.getName().equals(name)) 94 .findFirst(); 95 96 Method m = om.get(); 97 return Op.ofMethod(m).get(); 98 } 99 }