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.op.CoreOp.FuncOp; 15 import static jdk.incubator.code.op.CoreOp.VarAccessOp.VarLoadOp; 16 import static jdk.incubator.code.op.CoreOp.VarAccessOp.VarStoreOp; 17 import static jdk.incubator.code.op.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 f.writeTo(System.out); 40 FuncOp lf = lower(f); 41 lf.writeTo(System.out); 42 43 FuncOp f2 = f.transform(TestRemoveFinalVars::rmFinalVars); 44 f2.writeTo(System.out); 45 FuncOp lf2 = lower(f2); 46 lf2.writeTo(System.out); 47 48 Assert.assertEquals(Interpreter.invoke(MethodHandles.lookup(), lf), Interpreter.invoke(MethodHandles.lookup(), lf2)); 49 50 SSA.transform(lower(f)).writeTo(System.out); 51 } 52 53 static FuncOp lower(FuncOp funcOp) { 54 return funcOp.transform(OpTransformer.LOWERING_TRANSFORMER); 55 } 56 57 static Block.Builder rmFinalVars(Block.Builder block, Op op) { 58 if (op instanceof VarOp varOp) { 59 // Is the variable stored to? If not we can remove it 60 // otherwise, it's not considered final and we copy it 61 if (isValueUsedWithOp(varOp.result(), o -> o instanceof VarStoreOp)) { 62 block.op(varOp); 63 } 64 } else if (op instanceof VarLoadOp varLoadOp) { 65 // If the variable is not stored to 66 if (!isValueUsedWithOp(varLoadOp.varOp().result(), o -> o instanceof VarStoreOp)) { 67 // Map result of load from variable to the value that initialized the variable 68 // Subsequently encountered input operations using the result will be copied 69 // to output operations using the mapped value 70 CopyContext cc = block.context(); 71 cc.mapValue(varLoadOp.result(), cc.getValue(varLoadOp.varOp().operands().get(0))); 72 } else { 73 block.op(varLoadOp); 74 } 75 } else { 76 block.op(op); 77 } 78 return block; 79 } 80 81 private static boolean isValueUsedWithOp(Value value, Predicate<Op> opPredicate) { 82 for (Op.Result user : value.uses()) { 83 if (opPredicate.test(user.op())) { 84 return true; 85 } 86 } 87 return false; 88 } 89 90 static FuncOp getFuncOp(Class<?> c, String name) { 91 Optional<Method> om = Stream.of(c.getDeclaredMethods()) 92 .filter(m -> m.getName().equals(name)) 93 .findFirst(); 94 95 Method m = om.get(); 96 return Op.ofMethod(m).get(); 97 } 98 }