diff options
Diffstat (limited to 'test/943-private-recursive-jit/src/Main.java')
-rw-r--r-- | test/943-private-recursive-jit/src/Main.java | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/test/943-private-recursive-jit/src/Main.java b/test/943-private-recursive-jit/src/Main.java new file mode 100644 index 0000000000..8fa534d997 --- /dev/null +++ b/test/943-private-recursive-jit/src/Main.java @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.Base64; +import java.util.function.Consumer; +import java.lang.reflect.Method; + +public class Main { + static final boolean ALWAYS_PRINT = false; + + // import java.util.function.Consumer; + // class Transform { + // public void sayHi(int recur, Consumer<String> reporter, Runnable r) { + // privateSayHi(recur, reporter, r); + // } + // private void privateSayHi(int recur, Consumer<String> reporter, Runnable r) { + // reporter.accpet("hello" + recur + " - transformed"); + // if (recur == 1) { + // r.run(); + // privateSayHi(recur - 1, reporter, r); + // } else if (recur != 0) { + // privateSayHi(recur - 1, reporter, r); + // } + // reporter.accept("goodbye" + recur + " - transformed"); + // } + // } + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQANAoADgAbCgANABwHAB0KAAMAGwgAHgoAAwAfCgADACAIACEKAAMAIgsAIwAkCwAl" + + "ACYIACcHACgHACkBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQAFc2F5" + + "SGkBADUoSUxqYXZhL3V0aWwvZnVuY3Rpb24vQ29uc3VtZXI7TGphdmEvbGFuZy9SdW5uYWJsZTsp" + + "VgEACVNpZ25hdHVyZQEASShJTGphdmEvdXRpbC9mdW5jdGlvbi9Db25zdW1lcjxMamF2YS9sYW5n" + + "L1N0cmluZzs+O0xqYXZhL2xhbmcvUnVubmFibGU7KVYBAAxwcml2YXRlU2F5SGkBAA1TdGFja01h" + + "cFRhYmxlAQAKU291cmNlRmlsZQEADlRyYW5zZm9ybS5qYXZhDAAPABAMABcAFAEAF2phdmEvbGFu" + + "Zy9TdHJpbmdCdWlsZGVyAQAFaGVsbG8MACoAKwwAKgAsAQAOIC0gdHJhbnNmb3JtZWQMAC0ALgcA" + + "LwwAMAAxBwAyDAAzABABAAdnb29kYnllAQAJVHJhbnNmb3JtAQAQamF2YS9sYW5nL09iamVjdAEA" + + "BmFwcGVuZAEALShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwEA" + + "HChJKUxqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcjsBAAh0b1N0cmluZwEAFCgpTGphdmEvbGFuZy9T" + + "dHJpbmc7AQAbamF2YS91dGlsL2Z1bmN0aW9uL0NvbnN1bWVyAQAGYWNjZXB0AQAVKExqYXZhL2xh" + + "bmcvT2JqZWN0OylWAQASamF2YS9sYW5nL1J1bm5hYmxlAQADcnVuACAADQAOAAAAAAADAAAADwAQ" + + "AAEAEQAAAB0AAQABAAAABSq3AAGxAAAAAQASAAAABgABAAAAAgABABMAFAACABEAAAAkAAQABAAA" + + "AAgqGywttwACsQAAAAEAEgAAAAoAAgAAAAQABwAFABUAAAACABYAAgAXABQAAgARAAAAnwAEAAQA" + + "AABhLLsAA1m3AAQSBbYABhu2AAcSCLYABrYACbkACgIAGwSgABUtuQALAQAqGwRkLC23AAKnABAb" + + "mQAMKhsEZCwttwACLLsAA1m3AAQSDLYABhu2AAcSCLYABrYACbkACgIAsQAAAAIAEgAAACIACAAA" + + "AAcAHgAIACMACQApAAoANQALADkADABCAA4AYAAPABgAAAAEAAI1DAAVAAAAAgAWAAEAGQAAAAIA" + + "Gg=="); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQCevtlr8B0kh/duuDYqXkGz/w9lMmtCCuRoBQAAcAAAAHhWNBIAAAAAAAAAALAEAAAg" + + "AAAAcAAAAAkAAADwAAAABgAAABQBAAAAAAAAAAAAAAoAAABcAQAAAQAAAKwBAACcAwAAzAEAAPYC" + + "AAAGAwAACgMAAA4DAAARAwAAGQMAAB0DAAAgAwAAIwMAACcDAAArAwAAOAMAAFcDAABrAwAAgQMA" + + "AJUDAACwAwAAzgMAAO0DAAD9AwAAAAQAAAYEAAAKBAAAEgQAABoEAAAuBAAANwQAAD4EAABMBAAA" + + "UQQAAFgEAABiBAAABgAAAAoAAAALAAAADAAAAA0AAAAOAAAADwAAABEAAAATAAAABwAAAAUAAAAA" + + "AAAACAAAAAYAAADUAgAACQAAAAYAAADcAgAAEwAAAAgAAAAAAAAAFAAAAAgAAADkAgAAFQAAAAgA" + + "AADwAgAAAQADAAQAAAABAAQAGwAAAAEABAAdAAAAAwADAAQAAAAEAAMAHAAAAAYAAwAEAAAABgAB" + + "ABcAAAAGAAIAFwAAAAYAAAAeAAAABwAFABYAAAABAAAAAAAAAAMAAAAAAAAAEgAAALQCAACeBAAA" + + "AAAAAAEAAACKBAAAAQABAAEAAABpBAAABAAAAHAQAwAAAA4ABgAEAAQAAABuBAAAUAAAACIABgBw" + + "EAUAAAAbARoAAABuIAcAEAAMAG4gBgAwAAwAGwEAAAAAbiAHABAADABuEAgAAAAMAHIgCQAEABIQ" + + "MwMpAHIQBAAFANgAA/9wQAEAAlQiAAYAcBAFAAAAGwEZAAAAbiAHABAADABuIAYAMAAMABsBAAAA" + + "AG4gBwAQAAwAbhAIAAAADAByIAkABAAOADgD4f/YAAP/cEABAAJUKNoEAAQABAAAAIEEAAAEAAAA" + + "cEABABAyDgAAAAAAAAAAAAIAAAAAAAAAAQAAAMwBAAACAAAAzAEAAAEAAAAAAAAAAQAAAAUAAAAD" + + "AAAAAAAHAAQAAAABAAAAAwAOIC0gdHJhbnNmb3JtZWQAAihJAAIpVgABPAAGPGluaXQ+AAI+OwAB" + + "SQABTAACTEkAAkxMAAtMVHJhbnNmb3JtOwAdTGRhbHZpay9hbm5vdGF0aW9uL1NpZ25hdHVyZTsA" + + "EkxqYXZhL2xhbmcvT2JqZWN0OwAUTGphdmEvbGFuZy9SdW5uYWJsZTsAEkxqYXZhL2xhbmcvU3Ry" + + "aW5nOwAZTGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwAcTGphdmEvdXRpbC9mdW5jdGlvbi9Db25z" + + "dW1lcgAdTGphdmEvdXRpbC9mdW5jdGlvbi9Db25zdW1lcjsADlRyYW5zZm9ybS5qYXZhAAFWAARW" + + "SUxMAAJWTAAGYWNjZXB0AAZhcHBlbmQAEmVtaXR0ZXI6IGphY2stNC4yNAAHZ29vZGJ5ZQAFaGVs" + + "bG8ADHByaXZhdGVTYXlIaQADcnVuAAVzYXlIaQAIdG9TdHJpbmcABXZhbHVlAAIABw4ABwMAAAAH" + + "DgEeDzw8XQEeDxktAAQDAAAABw48AAICAR8cBxcBFxAXAxcOFwUXDRcCAAACAQCAgATUAwEC7AMC" + + "AZwFDwAAAAAAAAABAAAAAAAAAAEAAAAgAAAAcAAAAAIAAAAJAAAA8AAAAAMAAAAGAAAAFAEAAAUA" + + "AAAKAAAAXAEAAAYAAAABAAAArAEAAAMQAAABAAAAzAEAAAEgAAADAAAA1AEAAAYgAAABAAAAtAIA" + + "AAEQAAAEAAAA1AIAAAIgAAAgAAAA9gIAAAMgAAADAAAAaQQAAAQgAAABAAAAigQAAAAgAAABAAAA" + + "ngQAAAAQAAABAAAAsAQAAA=="); + + // A class that we can use to keep track of the output of this test. + private static class TestWatcher implements Consumer<String> { + private StringBuilder sb; + public TestWatcher() { + sb = new StringBuilder(); + } + + @Override + public void accept(String s) { + if (Main.ALWAYS_PRINT) { + System.out.println(s); + } + sb.append(s); + sb.append('\n'); + } + + public String getOutput() { + return sb.toString(); + } + + public void clear() { + sb = new StringBuilder(); + } + } + + public static void main(String[] args) { + doTest(new Transform()); + } + + private static boolean retry = false; + + public static void doTest(Transform t) { + final TestWatcher reporter = new TestWatcher(); + Method say_hi_method; + Method private_say_hi_method; + // Figure out if we can even JIT at all. + final boolean has_jit = hasJit(); + try { + say_hi_method = Transform.class.getDeclaredMethod( + "sayHi", int.class, Consumer.class, Runnable.class); + private_say_hi_method = Transform.class.getDeclaredMethod( + "privateSayHi", int.class, Consumer.class, Runnable.class); + } catch (Exception e) { + System.out.println("Unable to find methods!"); + e.printStackTrace(); + return; + } + // Makes sure the stack is the way we want it for the test and does the redefinition. It will + // set the retry boolean to true if we need to go around again due to jit code being GCd. + Runnable do_redefinition = () -> { + if (has_jit && + (Main.isInterpretedFunction(say_hi_method, true) || + Main.isInterpretedFunction(private_say_hi_method, true))) { + // Try again. We are not running the right jitted methods/cannot redefine them now. + retry = true; + } else { + // Actually do the redefinition. The stack looks good. + retry = false; + reporter.accept("transforming calling function"); + doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); + } + }; + do { + // Run ensureJitCompiled here since it might get GCd + ensureJitCompiled(Transform.class, "sayHi"); + ensureJitCompiled(Transform.class, "privateSayHi"); + // Clear output. + reporter.clear(); + t.sayHi(2, reporter, () -> { reporter.accept("Not doing anything here"); }); + t.sayHi(2, reporter, do_redefinition); + t.sayHi(2, reporter, () -> { reporter.accept("Not doing anything here"); }); + } while(retry); + System.out.println(reporter.getOutput()); + } + + private static native boolean hasJit(); + + private static native boolean isInterpretedFunction(Method m, boolean require_deoptimizable); + + private static native void ensureJitCompiled(Class c, String name); + + // Transforms the class + private static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); +} |