diff options
Diffstat (limited to 'test')
176 files changed, 4776 insertions, 261 deletions
diff --git a/test/004-NativeAllocations/src/Main.java b/test/004-NativeAllocations/src/Main.java index 92f4e21f40..8712755125 100644 --- a/test/004-NativeAllocations/src/Main.java +++ b/test/004-NativeAllocations/src/Main.java @@ -16,6 +16,7 @@ import java.lang.reflect.*; import java.lang.Runtime; +import dalvik.system.VMRuntime; public class Main { static Object nativeLock = new Object(); @@ -33,10 +34,19 @@ public class Main { NativeAllocation(int bytes, boolean testingDeadlock) throws Exception { this.bytes = bytes; register_native_allocation.invoke(runtime, bytes); + + // Register native allocation can only provide guarantees bounding + // the maximum outstanding allocations if finalizers don't time + // out. In case finalizers have timed out, wait longer for them + // now to complete so we can test the guarantees. + if (!testingDeadlock) { + VMRuntime.runFinalization(0); + } + synchronized (nativeLock) { if (!testingDeadlock) { nativeBytes += bytes; - if (nativeBytes > maxMem) { + if (nativeBytes > 2 * maxMem) { throw new OutOfMemoryError(); } } diff --git a/test/008-exceptions/expected.txt b/test/008-exceptions/expected.txt index 083ecf7ced..fcf2ef49f3 100644 --- a/test/008-exceptions/expected.txt +++ b/test/008-exceptions/expected.txt @@ -1,11 +1,11 @@ Got an NPE: second throw java.lang.NullPointerException: second throw - at Main.catchAndRethrow(Main.java:77) - at Main.exceptions_007(Main.java:59) - at Main.main(Main.java:67) + at Main.catchAndRethrow(Main.java:94) + at Main.exceptions_007(Main.java:74) + at Main.main(Main.java:82) Caused by: java.lang.NullPointerException: first throw - at Main.throwNullPointerException(Main.java:84) - at Main.catchAndRethrow(Main.java:74) + at Main.throwNullPointerException(Main.java:101) + at Main.catchAndRethrow(Main.java:91) ... 2 more Static Init BadError: This is bad by convention: BadInit @@ -15,3 +15,11 @@ Static BadInitNoStringInit BadErrorNoStringInit: This is bad by convention java.lang.NoClassDefFoundError: BadInitNoStringInit BadErrorNoStringInit: This is bad by convention +BadSuperClass Static Init +BadError: This is bad by convention: BadInit +MultiDexBadInit Static Init +java.lang.Error: MultiDexBadInit +java.lang.NoClassDefFoundError: MultiDexBadInit + cause: java.lang.Error: MultiDexBadInit +java.lang.NoClassDefFoundError: MultiDexBadInit + cause: java.lang.Error: MultiDexBadInit diff --git a/test/008-exceptions/multidex.jpp b/test/008-exceptions/multidex.jpp new file mode 100644 index 0000000000..a3746f5149 --- /dev/null +++ b/test/008-exceptions/multidex.jpp @@ -0,0 +1,27 @@ +BadError: + @@com.android.jack.annotations.ForceInMainDex + class BadError +BadInit: + @@com.android.jack.annotations.ForceInMainDex + class BadInit +BadErrorNoStringInit: + @@com.android.jack.annotations.ForceInMainDex + class BadErrorNoStringInit +BadInitNoStringInit: + @@com.android.jack.annotations.ForceInMainDex + class BadInitNoStringInit +BadSuperClass: + @@com.android.jack.annotations.ForceInMainDex + class BadSuperClass +DerivedFromBadSuperClass: + @@com.android.jack.annotations.ForceInMainDex + class DerivedFromBadSuperClass +Main: + @@com.android.jack.annotations.ForceInMainDex + class Main +MultiDexBadInit: + @@com.android.jack.annotations.ForceInMainDex + class MultiDexBadInit +MultiDexBadInitWrapper1: + @@com.android.jack.annotations.ForceInMainDex + class MultiDexBadInitWrapper1 diff --git a/test/008-exceptions/src-multidex/MultiDexBadInitWrapper2.java b/test/008-exceptions/src-multidex/MultiDexBadInitWrapper2.java new file mode 100644 index 0000000000..f3953bd4c7 --- /dev/null +++ b/test/008-exceptions/src-multidex/MultiDexBadInitWrapper2.java @@ -0,0 +1,24 @@ +/* + * 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. + */ + +class MultiDexBadInitWrapper2 { + public static void setDummy(int value) { + if (doThrow) { throw new Error(); } + MultiDexBadInit.dummy = value; + } + + public static boolean doThrow = false; +} diff --git a/test/008-exceptions/src/Main.java b/test/008-exceptions/src/Main.java index b8231f12bd..74af00ccf7 100644 --- a/test/008-exceptions/src/Main.java +++ b/test/008-exceptions/src/Main.java @@ -50,6 +50,21 @@ class BadInitNoStringInit { } } +// A class that throws BadError during static initialization, serving as a super class. +class BadSuperClass { + static int dummy; + static { + System.out.println("BadSuperClass Static Init"); + if (true) { + throw new BadError("BadInit"); + } + } +} + +// A class that derives from BadSuperClass. +class DerivedFromBadSuperClass extends BadSuperClass { +} + /** * Exceptions across method calls */ @@ -63,10 +78,12 @@ public class Main { npe.printStackTrace(System.out); } } - public static void main (String args[]) { + public static void main(String args[]) { exceptions_007(); exceptionsRethrowClassInitFailure(); exceptionsRethrowClassInitFailureNoStringInit(); + exceptionsForSuperClassInitFailure(); + exceptionsInMultiDex(); } private static void catchAndRethrow() { @@ -129,4 +146,70 @@ public class Main { error.printStackTrace(System.out); } } + + private static void exceptionsForSuperClassInitFailure() { + try { + // Resolve DerivedFromBadSuperClass. + BadSuperClass.dummy = 1; + throw new IllegalStateException("Should not reach here."); + } catch (BadError e) { + System.out.println(e); + } catch (Throwable t) { + t.printStackTrace(); + } + try { + // Before splitting mirror::Class::kStatusError into + // kStatusErrorUnresolved and kStatusErrorResolved, + // this would trigger a + // CHECK(super_class->IsResolved()) + // failure in + // ClassLinker::LoadSuperAndInterfaces(). + // After the change we're getting either VerifyError + // (for Optimizing) or NoClassDefFoundError wrapping + // BadError (for interpreter or JIT). + new DerivedFromBadSuperClass(); + throw new IllegalStateException("Should not reach here."); + } catch (NoClassDefFoundError ncdfe) { + if (!(ncdfe.getCause() instanceof BadError)) { + ncdfe.getCause().printStackTrace(); + } + } catch (VerifyError e) { + } catch (Throwable t) { + t.printStackTrace(); + } + } + + private static void exceptionsInMultiDex() { + try { + MultiDexBadInit.dummy = 1; + throw new IllegalStateException("Should not reach here."); + } catch (Error e) { + System.out.println(e); + } catch (Throwable t) { + t.printStackTrace(); + } + // Before splitting mirror::Class::kStatusError into + // kStatusErrorUnresolved and kStatusErrorResolved, + // the exception from wrapper 1 would have been + // wrapped in NoClassDefFoundError but the exception + // from wrapper 2 would have been unwrapped. + try { + MultiDexBadInitWrapper1.setDummy(1); + throw new IllegalStateException("Should not reach here."); + } catch (NoClassDefFoundError ncdfe) { + System.out.println(ncdfe); + System.out.println(" cause: " + ncdfe.getCause()); + } catch (Throwable t) { + t.printStackTrace(); + } + try { + MultiDexBadInitWrapper2.setDummy(1); + throw new IllegalStateException("Should not reach here."); + } catch (NoClassDefFoundError ncdfe) { + System.out.println(ncdfe); + System.out.println(" cause: " + ncdfe.getCause()); + } catch (Throwable t) { + t.printStackTrace(); + } + } } diff --git a/test/008-exceptions/src/MultiDexBadInit.java b/test/008-exceptions/src/MultiDexBadInit.java new file mode 100644 index 0000000000..e3ebb9ca45 --- /dev/null +++ b/test/008-exceptions/src/MultiDexBadInit.java @@ -0,0 +1,25 @@ +/* + * 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. + */ + +class MultiDexBadInit { + static int dummy; + static { + System.out.println("MultiDexBadInit Static Init"); + if (true) { + throw new Error("MultiDexBadInit"); + } + } +} diff --git a/test/008-exceptions/src/MultiDexBadInitWrapper1.java b/test/008-exceptions/src/MultiDexBadInitWrapper1.java new file mode 100644 index 0000000000..059e6a3d7d --- /dev/null +++ b/test/008-exceptions/src/MultiDexBadInitWrapper1.java @@ -0,0 +1,24 @@ +/* + * 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. + */ + +class MultiDexBadInitWrapper1 { + public static void setDummy(int value) { + if (doThrow) { throw new Error(); } + MultiDexBadInit.dummy = value; + } + + public static boolean doThrow = false; +} diff --git a/test/082-inline-execute/src/Main.java b/test/082-inline-execute/src/Main.java index 06f193af32..072f0e68ee 100644 --- a/test/082-inline-execute/src/Main.java +++ b/test/082-inline-execute/src/Main.java @@ -535,6 +535,8 @@ public class Main { Assert.assertEquals(Math.min(0.0f, Float.MAX_VALUE), 0.0f); Assert.assertEquals(Math.min(Float.MIN_VALUE, 0.0f), 0.0f); Assert.assertEquals(Math.min(Float.MIN_VALUE, Float.MAX_VALUE), Float.MIN_VALUE); + // Should not have flush-to-zero behavior. + Assert.assertEquals(Math.min(Float.MIN_VALUE, Float.MIN_VALUE), Float.MIN_VALUE); } public static void test_Math_max_F() { @@ -548,8 +550,10 @@ public class Main { Assert.assertEquals(Math.max(1.0f, 0.0f), 1.0f); Assert.assertEquals(Math.max(0.0f, 1.0f), 1.0f); Assert.assertEquals(Math.max(0.0f, Float.MAX_VALUE), Float.MAX_VALUE); - Assert.assertEquals(Math.max(Float.MIN_VALUE, 0.0f), Float.MIN_VALUE); Assert.assertEquals(Math.max(Float.MIN_VALUE, Float.MAX_VALUE), Float.MAX_VALUE); + // Should not have flush-to-zero behavior. + Assert.assertEquals(Math.max(Float.MIN_VALUE, 0.0f), Float.MIN_VALUE); + Assert.assertEquals(Math.max(Float.MIN_VALUE, Float.MIN_VALUE), Float.MIN_VALUE); } public static void test_Math_min_D() { @@ -565,6 +569,8 @@ public class Main { Assert.assertEquals(Math.min(0.0d, Double.MAX_VALUE), 0.0d); Assert.assertEquals(Math.min(Double.MIN_VALUE, 0.0d), 0.0d); Assert.assertEquals(Math.min(Double.MIN_VALUE, Double.MAX_VALUE), Double.MIN_VALUE); + // Should not have flush-to-zero behavior. + Assert.assertEquals(Math.min(Double.MIN_VALUE, Double.MIN_VALUE), Double.MIN_VALUE); } public static void test_Math_max_D() { @@ -580,6 +586,9 @@ public class Main { Assert.assertEquals(Math.max(0.0d, Double.MAX_VALUE), Double.MAX_VALUE); Assert.assertEquals(Math.max(Double.MIN_VALUE, 0.0d), Double.MIN_VALUE); Assert.assertEquals(Math.max(Double.MIN_VALUE, Double.MAX_VALUE), Double.MAX_VALUE); + // Should not have flush-to-zero behavior. + Assert.assertEquals(Math.max(Double.MIN_VALUE, 0.0d), Double.MIN_VALUE); + Assert.assertEquals(Math.max(Double.MIN_VALUE, Double.MIN_VALUE), Double.MIN_VALUE); } public static void test_Math_sqrt() { @@ -730,16 +739,19 @@ public class Main { Math.rint(+2.1); Assert.assertEquals(Math.rint(+0.0), +0.0d, 0.0); Assert.assertEquals(Math.rint(-0.0), -0.0d, 0.0); + Assert.assertEquals(Math.rint(+0.5), +0.0d, 0.0); // expects tie-to-even Assert.assertEquals(Math.rint(+2.0), +2.0d, 0.0); Assert.assertEquals(Math.rint(+2.1), +2.0d, 0.0); - Assert.assertEquals(Math.rint(+2.5), +2.0d, 0.0); + Assert.assertEquals(Math.rint(+2.5), +2.0d, 0.0); // expects tie-to-even Assert.assertEquals(Math.rint(+2.9), +3.0d, 0.0); Assert.assertEquals(Math.rint(+3.0), +3.0d, 0.0); + Assert.assertEquals(Math.rint(+3.5), +4.0d, 0.0); // expects tie-to-even Assert.assertEquals(Math.rint(-2.0), -2.0d, 0.0); Assert.assertEquals(Math.rint(-2.1), -2.0d, 0.0); - Assert.assertEquals(Math.rint(-2.5), -2.0d, 0.0); + Assert.assertEquals(Math.rint(-2.5), -2.0d, 0.0); // expects tie-to-even Assert.assertEquals(Math.rint(-2.9), -3.0d, 0.0); Assert.assertEquals(Math.rint(-3.0), -3.0d, 0.0); + Assert.assertEquals(Math.rint(-3.5), -4.0d, 0.0); // expects tie-to-even // 2^52 - 1.5 Assert.assertEquals(Math.rint(Double.longBitsToDouble(0x432FFFFFFFFFFFFDl)), Double.longBitsToDouble(0x432FFFFFFFFFFFFCl), 0.0); diff --git a/test/142-classloader2/expected.txt b/test/142-classloader2/expected.txt index 86f5e220e2..056d9785de 100644 --- a/test/142-classloader2/expected.txt +++ b/test/142-classloader2/expected.txt @@ -1 +1,5 @@ +Loaded class B. +Caught VerifyError. +Loaded class B. +Caught wrapped VerifyError. Everything OK. diff --git a/test/142-classloader2/src/Main.java b/test/142-classloader2/src/Main.java index 80b00e7dd2..a0c77645a3 100644 --- a/test/142-classloader2/src/Main.java +++ b/test/142-classloader2/src/Main.java @@ -74,16 +74,25 @@ public class Main { // Try to load a dex file with bad dex code. Use new instance to force verification. try { Class<?> badClass = Main.class.getClassLoader().loadClass("B"); + System.out.println("Loaded class B."); badClass.newInstance(); - System.out.println("Should not be able to load class from bad dex file."); + System.out.println("Should not be able to instantiate B with bad dex bytecode."); } catch (VerifyError e) { + System.out.println("Caught VerifyError."); } // Make sure the same error is rethrown when reloading the bad class. try { Class<?> badClass = Main.class.getClassLoader().loadClass("B"); - System.out.println("Should not be able to load class from bad dex file."); - } catch (VerifyError e) { + System.out.println("Loaded class B."); + badClass.newInstance(); + System.out.println("Should not be able to instantiate B with bad dex bytecode."); + } catch (NoClassDefFoundError e) { + if (e.getCause() instanceof VerifyError) { + System.out.println("Caught wrapped VerifyError."); + } else { + e.printStackTrace(); + } } System.out.println("Everything OK."); diff --git a/test/154-gc-loop/expected.txt b/test/154-gc-loop/expected.txt new file mode 100644 index 0000000000..6106818c79 --- /dev/null +++ b/test/154-gc-loop/expected.txt @@ -0,0 +1,2 @@ +JNI_OnLoad called +Finalize count too large: false diff --git a/test/154-gc-loop/heap_interface.cc b/test/154-gc-loop/heap_interface.cc new file mode 100644 index 0000000000..8d610a87fa --- /dev/null +++ b/test/154-gc-loop/heap_interface.cc @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2015 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. + */ + +#include "gc/heap.h" +#include "runtime.h" + +namespace art { +namespace { + +extern "C" JNIEXPORT void JNICALL Java_Main_backgroundProcessState(JNIEnv*, jclass) { + Runtime::Current()->UpdateProcessState(kProcessStateJankImperceptible); +} + +} // namespace +} // namespace art diff --git a/test/154-gc-loop/info.txt b/test/154-gc-loop/info.txt new file mode 100644 index 0000000000..f599db1d01 --- /dev/null +++ b/test/154-gc-loop/info.txt @@ -0,0 +1 @@ +Test that GC doesn't happen too often for a few small allocations. diff --git a/test/154-gc-loop/src/Main.java b/test/154-gc-loop/src/Main.java new file mode 100644 index 0000000000..3a256c109e --- /dev/null +++ b/test/154-gc-loop/src/Main.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2017 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.lang.ref.WeakReference; + +public class Main { + static final class GcWatcher { + protected void finalize() throws Throwable { + watcher = new WeakReference<GcWatcher>(new GcWatcher()); + ++finalizeCounter; + } + } + static WeakReference<GcWatcher> watcher = new WeakReference<GcWatcher>(new GcWatcher()); + static Object o = new Object(); + static int finalizeCounter = 0; + + public static void main(String[] args) { + System.loadLibrary(args[0]); + backgroundProcessState(); + try { + Runtime.getRuntime().gc(); + for (int i = 0; i < 10; ++i) { + o = new Object(); + Thread.sleep(1000); + } + } catch (Exception e) {} + System.out.println("Finalize count too large: " + + ((finalizeCounter >= 10) ? Integer.toString(finalizeCounter) : "false")); + } + + private static native void backgroundProcessState(); +} diff --git a/test/466-get-live-vreg/get_live_vreg_jni.cc b/test/466-get-live-vreg/get_live_vreg_jni.cc index d3a033b12a..6cea673b41 100644 --- a/test/466-get-live-vreg/get_live_vreg_jni.cc +++ b/test/466-get-live-vreg/get_live_vreg_jni.cc @@ -47,7 +47,7 @@ class TestVisitor : public StackVisitor { uint32_t value = 0; if (GetCurrentQuickFrame() != nullptr && GetCurrentOatQuickMethodHeader()->IsOptimized() && - !Runtime::Current()->IsDebuggable()) { + !Runtime::Current()->IsJavaDebuggable()) { CHECK_EQ(GetVReg(m, dex_register_of_first_parameter, kIntVReg, &value), false); } else { CHECK(GetVReg(m, dex_register_of_first_parameter, kIntVReg, &value)); diff --git a/test/482-checker-loop-back-edge-use/src/Main.java b/test/482-checker-loop-back-edge-use/src/Main.java index 65dfd411fd..86977d1b8e 100644 --- a/test/482-checker-loop-back-edge-use/src/Main.java +++ b/test/482-checker-loop-back-edge-use/src/Main.java @@ -164,6 +164,12 @@ public class Main { } } + + static boolean $opt$noinline$ensureSideEffects() { + if (doThrow) throw new Error(""); + return true; + } + /// CHECK-START: void Main.loop9() liveness (after) /// CHECK: <<Arg:z\d+>> StaticFieldGet liveness:<<ArgLiv:\d+>> ranges:{[<<ArgLiv>>,<<ArgLoopUse:\d+>>)} uses:[<<ArgUse:\d+>>,<<ArgLoopUse>>] /// CHECK: If [<<Arg>>] liveness:<<IfLiv:\d+>> @@ -178,7 +184,7 @@ public class Main { // Add some code at entry to avoid having the entry block be a pre header. // This avoids having to create a synthesized block. System.out.println("Enter"); - while (Runtime.getRuntime() != null) { + while ($opt$noinline$ensureSideEffects()) { // 'incoming' must only have a use in the inner loop. boolean incoming = field; while (incoming) {} @@ -189,4 +195,5 @@ public class Main { } static boolean field; + static boolean doThrow = false; } diff --git a/test/552-checker-sharpening/src/Main.java b/test/552-checker-sharpening/src/Main.java index db437686f0..dd77423870 100644 --- a/test/552-checker-sharpening/src/Main.java +++ b/test/552-checker-sharpening/src/Main.java @@ -52,7 +52,6 @@ public class Main { /// CHECK: InvokeStaticOrDirect method_load_kind:dex_cache_pc_relative /// CHECK-START-MIPS: int Main.testSimple(int) sharpening (after) - /// CHECK-NOT: MipsDexCacheArraysBase /// CHECK: InvokeStaticOrDirect method_load_kind:dex_cache_pc_relative /// CHECK-START-MIPS64: int Main.testSimple(int) sharpening (after) @@ -69,10 +68,6 @@ public class Main { /// CHECK: ArmDexCacheArraysBase /// CHECK-NOT: ArmDexCacheArraysBase - /// CHECK-START-MIPS: int Main.testSimple(int) dex_cache_array_fixups_mips (after) - /// CHECK: MipsDexCacheArraysBase - /// CHECK-NOT: MipsDexCacheArraysBase - /// CHECK-START-X86: int Main.testSimple(int) pc_relative_fixups_x86 (after) /// CHECK: X86ComputeBaseMethodAddress /// CHECK-NOT: X86ComputeBaseMethodAddress @@ -95,7 +90,6 @@ public class Main { /// CHECK: InvokeStaticOrDirect method_load_kind:dex_cache_pc_relative /// CHECK-START-MIPS: int Main.testDiamond(boolean, int) sharpening (after) - /// CHECK-NOT: MipsDexCacheArraysBase /// CHECK: InvokeStaticOrDirect method_load_kind:dex_cache_pc_relative /// CHECK: InvokeStaticOrDirect method_load_kind:dex_cache_pc_relative @@ -120,14 +114,6 @@ public class Main { /// CHECK: ArmDexCacheArraysBase /// CHECK-NEXT: If - /// CHECK-START-MIPS: int Main.testDiamond(boolean, int) dex_cache_array_fixups_mips (after) - /// CHECK: MipsDexCacheArraysBase - /// CHECK-NOT: MipsDexCacheArraysBase - - /// CHECK-START-MIPS: int Main.testDiamond(boolean, int) dex_cache_array_fixups_mips (after) - /// CHECK: MipsDexCacheArraysBase - /// CHECK-NEXT: If - /// CHECK-START-X86: int Main.testDiamond(boolean, int) pc_relative_fixups_x86 (after) /// CHECK: X86ComputeBaseMethodAddress /// CHECK-NOT: X86ComputeBaseMethodAddress @@ -182,24 +168,6 @@ public class Main { /// CHECK: begin_block /// CHECK: InvokeStaticOrDirect method_load_kind:dex_cache_pc_relative - /// CHECK-START-MIPS: int Main.testLoop(int[], int) dex_cache_array_fixups_mips (before) - /// CHECK-NOT: MipsDexCacheArraysBase - - /// CHECK-START-MIPS: int Main.testLoop(int[], int) dex_cache_array_fixups_mips (after) - /// CHECK: MipsDexCacheArraysBase - /// CHECK-NOT: MipsDexCacheArraysBase - - /// CHECK-START-MIPS: int Main.testLoop(int[], int) dex_cache_array_fixups_mips (after) - /// CHECK: InvokeStaticOrDirect - /// CHECK-NOT: InvokeStaticOrDirect - - /// CHECK-START-MIPS: int Main.testLoop(int[], int) dex_cache_array_fixups_mips (after) - /// CHECK: ArrayLength - /// CHECK-NEXT: MipsDexCacheArraysBase - /// CHECK-NEXT: Goto - /// CHECK: begin_block - /// CHECK: InvokeStaticOrDirect method_load_kind:dex_cache_pc_relative - public static int testLoop(int[] array, int x) { // PC-relative bases used by ARM, MIPS and X86 should be pulled before the loop. for (int i : array) { @@ -228,16 +196,6 @@ public class Main { /// CHECK-NEXT: ArmDexCacheArraysBase /// CHECK-NEXT: Goto - /// CHECK-START-MIPS: int Main.testLoopWithDiamond(int[], boolean, int) dex_cache_array_fixups_mips (before) - /// CHECK-NOT: MipsDexCacheArraysBase - - /// CHECK-START-MIPS: int Main.testLoopWithDiamond(int[], boolean, int) dex_cache_array_fixups_mips (after) - /// CHECK: If - /// CHECK: begin_block - /// CHECK: ArrayLength - /// CHECK-NEXT: MipsDexCacheArraysBase - /// CHECK-NEXT: Goto - public static int testLoopWithDiamond(int[] array, boolean negate, int x) { // PC-relative bases used by ARM, MIPS and X86 should be pulled before the loop // but not outside the if. @@ -325,9 +283,6 @@ public class Main { return "non-boot-image-string"; } - /// CHECK-START: java.lang.Class Main.$noinline$getStringClass() sharpening (before) - /// CHECK: LoadClass load_kind:DexCacheViaMethod class_name:java.lang.String - /// CHECK-START-X86: java.lang.Class Main.$noinline$getStringClass() sharpening (after) // Note: load kind depends on PIC/non-PIC // TODO: Remove DexCacheViaMethod when read barrier config supports BootImageAddress. @@ -365,9 +320,6 @@ public class Main { return String.class; } - /// CHECK-START: java.lang.Class Main.$noinline$getOtherClass() sharpening (before) - /// CHECK: LoadClass load_kind:DexCacheViaMethod class_name:Other - /// CHECK-START-X86: java.lang.Class Main.$noinline$getOtherClass() sharpening (after) /// CHECK: LoadClass load_kind:BssEntry class_name:Other @@ -381,20 +333,12 @@ public class Main { /// CHECK-START-ARM: java.lang.Class Main.$noinline$getOtherClass() sharpening (after) /// CHECK: LoadClass load_kind:BssEntry class_name:Other - /// CHECK-START-ARM: java.lang.Class Main.$noinline$getOtherClass() dex_cache_array_fixups_arm (after) - /// CHECK-DAG: ArmDexCacheArraysBase - /// CHECK-DAG: LoadClass load_kind:BssEntry class_name:Other - /// CHECK-START-ARM64: java.lang.Class Main.$noinline$getOtherClass() sharpening (after) /// CHECK: LoadClass load_kind:BssEntry class_name:Other /// CHECK-START-MIPS: java.lang.Class Main.$noinline$getOtherClass() sharpening (after) /// CHECK: LoadClass load_kind:BssEntry class_name:Other - /// CHECK-START-MIPS: java.lang.Class Main.$noinline$getOtherClass() dex_cache_array_fixups_mips (after) - /// CHECK-DAG: MipsDexCacheArraysBase - /// CHECK-DAG: LoadClass load_kind:BssEntry class_name:Other - /// CHECK-START-MIPS64: java.lang.Class Main.$noinline$getOtherClass() sharpening (after) /// CHECK: LoadClass load_kind:BssEntry class_name:Other diff --git a/test/616-cha-abstract/expected.txt b/test/616-cha-abstract/expected.txt new file mode 100644 index 0000000000..6a5618ebc6 --- /dev/null +++ b/test/616-cha-abstract/expected.txt @@ -0,0 +1 @@ +JNI_OnLoad called diff --git a/test/616-cha-abstract/info.txt b/test/616-cha-abstract/info.txt new file mode 100644 index 0000000000..4f7e01391d --- /dev/null +++ b/test/616-cha-abstract/info.txt @@ -0,0 +1 @@ +Test for Class Hierarchy Analysis (CHA) on abstract method. diff --git a/test/616-cha-abstract/run b/test/616-cha-abstract/run new file mode 100644 index 0000000000..d8b4f0d26c --- /dev/null +++ b/test/616-cha-abstract/run @@ -0,0 +1,18 @@ +#!/bin/bash +# +# Copyright (C) 2017 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. + +# Run without an app image to prevent the classes to be loaded at startup. +exec ${RUN} "${@}" --no-app-image diff --git a/test/616-cha-abstract/src/Main.java b/test/616-cha-abstract/src/Main.java new file mode 100644 index 0000000000..e1d7db170d --- /dev/null +++ b/test/616-cha-abstract/src/Main.java @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2017 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. + */ + +abstract class Base { + abstract void foo(int i); + + void printError(String msg) { + System.out.println(msg); + } +} + +class Main1 extends Base { + void foo(int i) { + if (i != 1) { + printError("error1"); + } + } +} + +class Main2 extends Main1 { + void foo(int i) { + if (i != 2) { + printError("error2"); + } + } +} + +public class Main { + static Main1 sMain1; + static Main1 sMain2; + + static boolean sIsOptimizing = true; + static boolean sHasJIT = true; + static volatile boolean sOtherThreadStarted; + + private static void assertSingleImplementation(Class<?> clazz, String method_name, boolean b) { + if (hasSingleImplementation(clazz, method_name) != b) { + System.out.println(clazz + "." + method_name + + " doesn't have single implementation value of " + b); + } + } + + // sMain1.foo() will be always be Main1.foo() before Main2 is loaded/linked. + // So sMain1.foo() can be devirtualized to Main1.foo() and be inlined. + // After Dummy.createMain2() which links in Main2, live testOverride() on stack + // should be deoptimized. + static void testOverride(boolean createMain2, boolean wait, boolean setHasJIT) { + if (setHasJIT) { + if (isInterpreted()) { + sHasJIT = false; + } + return; + } + + if (createMain2 && (sIsOptimizing || sHasJIT)) { + assertIsManaged(); + } + + sMain1.foo(sMain1.getClass() == Main1.class ? 1 : 2); + + if (createMain2) { + // Wait for the other thread to start. + while (!sOtherThreadStarted); + // Create an Main2 instance and assign it to sMain2. + // sMain1 is kept the same. + sMain2 = Dummy.createMain2(); + // Wake up the other thread. + synchronized(Main.class) { + Main.class.notify(); + } + } else if (wait) { + // This is the other thread. + synchronized(Main.class) { + sOtherThreadStarted = true; + // Wait for Main2 to be linked and deoptimization is triggered. + try { + Main.class.wait(); + } catch (Exception e) { + } + } + } + + // There should be a deoptimization here right after Main2 is linked by + // calling Dummy.createMain2(), even though sMain1 didn't change. + // The behavior here would be different if inline-cache is used, which + // doesn't deoptimize since sMain1 still hits the type cache. + sMain1.foo(sMain1.getClass() == Main1.class ? 1 : 2); + if ((createMain2 || wait) && sHasJIT && !sIsOptimizing) { + // This method should be deoptimized right after Main2 is created. + assertIsInterpreted(); + } + + if (sMain2 != null) { + sMain2.foo(sMain2.getClass() == Main1.class ? 1 : 2); + } + } + + // Test scenarios under which CHA-based devirtualization happens, + // and class loading that overrides a method can invalidate compiled code. + public static void main(String[] args) { + System.loadLibrary(args[0]); + + if (isInterpreted()) { + sIsOptimizing = false; + } + + // sMain1 is an instance of Main1. Main2 hasn't bee loaded yet. + sMain1 = new Main1(); + + ensureJitCompiled(Main.class, "testOverride"); + testOverride(false, false, true); + + if (sHasJIT && !sIsOptimizing) { + assertSingleImplementation(Base.class, "foo", true); + assertSingleImplementation(Main1.class, "foo", true); + } else { + // Main2 is verified ahead-of-time so it's linked in already. + } + + // Create another thread that also calls sMain1.foo(). + // Try to test suspend and deopt another thread. + new Thread() { + public void run() { + testOverride(false, true, false); + } + }.start(); + + // This will create Main2 instance in the middle of testOverride(). + testOverride(true, false, false); + assertSingleImplementation(Base.class, "foo", false); + assertSingleImplementation(Main1.class, "foo", false); + } + + private static native void ensureJitCompiled(Class<?> itf, String method_name); + private static native void assertIsInterpreted(); + private static native void assertIsManaged(); + private static native boolean isInterpreted(); + private static native boolean hasSingleImplementation(Class<?> clazz, String method_name); +} + +// Put createMain2() in another class to avoid class loading due to verifier. +class Dummy { + static Main1 createMain2() { + return new Main2(); + } +} diff --git a/test/623-checker-loop-regressions/src/Main.java b/test/623-checker-loop-regressions/src/Main.java index 7cc0b8b652..7509d9b4f3 100644 --- a/test/623-checker-loop-regressions/src/Main.java +++ b/test/623-checker-loop-regressions/src/Main.java @@ -154,8 +154,8 @@ public class Main { /// CHECK-NOT: Phi // /// CHECK-START: int Main.polynomialInt() instruction_simplifier$after_bce (after) - /// CHECK-DAG: <<Int:i\d+>> IntConstant -45 loop:none - /// CHECK-DAG: Return [<<Int>>] loop:none + /// CHECK-DAG: <<Int:i\d+>> IntConstant -45 loop:none + /// CHECK-DAG: Return [<<Int>>] loop:none static int polynomialInt() { int x = 0; for (int i = 0; i < 10; i++) { @@ -164,6 +164,81 @@ public class Main { return x; } + // Regression test for b/34779592 (found with fuzz testing): overflow for last value + // of division truncates to zero, for multiplication it simply truncates. + // + /// CHECK-START: int Main.geoIntDivLastValue(int) loop_optimization (before) + /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: Phi loop:<<Loop>> outer_loop:none + // + /// CHECK-START: int Main.geoIntDivLastValue(int) loop_optimization (after) + /// CHECK-NOT: Phi + // + /// CHECK-START: int Main.geoIntDivLastValue(int) instruction_simplifier$after_bce (after) + /// CHECK-DAG: <<Int:i\d+>> IntConstant 0 loop:none + /// CHECK-DAG: Return [<<Int>>] loop:none + static int geoIntDivLastValue(int x) { + for (int i = 0; i < 2; i++) { + x /= 1081788608; + } + return x; + } + + /// CHECK-START: int Main.geoIntMulLastValue(int) loop_optimization (before) + /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: Phi loop:<<Loop>> outer_loop:none + // + /// CHECK-START: int Main.geoIntMulLastValue(int) loop_optimization (after) + /// CHECK-NOT: Phi + // + /// CHECK-START: int Main.geoIntMulLastValue(int) instruction_simplifier$after_bce (after) + /// CHECK-DAG: <<Par:i\d+>> ParameterValue loop:none + /// CHECK-DAG: <<Int:i\d+>> IntConstant -194211840 loop:none + /// CHECK-DAG: <<Mul:i\d+>> Mul [<<Par>>,<<Int>>] loop:none + /// CHECK-DAG: Return [<<Mul>>] loop:none + static int geoIntMulLastValue(int x) { + for (int i = 0; i < 2; i++) { + x *= 1081788608; + } + return x; + } + + /// CHECK-START: long Main.geoLongDivLastValue(long) loop_optimization (before) + /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: Phi loop:<<Loop>> outer_loop:none + // + /// CHECK-START: long Main.geoLongDivLastValue(long) loop_optimization (after) + /// CHECK-NOT: Phi + // + /// CHECK-START: long Main.geoLongDivLastValue(long) instruction_simplifier$after_bce (after) + /// CHECK-DAG: <<Long:j\d+>> LongConstant 0 loop:none + /// CHECK-DAG: Return [<<Long>>] loop:none + static long geoLongDivLastValue(long x) { + for (int i = 0; i < 10; i++) { + x /= 1081788608; + } + return x; + } + + /// CHECK-START: long Main.geoLongMulLastValue(long) loop_optimization (before) + /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none + /// CHECK-DAG: Phi loop:<<Loop>> outer_loop:none + // + /// CHECK-START: long Main.geoLongMulLastValue(long) loop_optimization (after) + /// CHECK-NOT: Phi + // + /// CHECK-START: long Main.geoLongMulLastValue(long) instruction_simplifier$after_bce (after) + /// CHECK-DAG: <<Par:j\d+>> ParameterValue loop:none + /// CHECK-DAG: <<Long:j\d+>> LongConstant -8070450532247928832 loop:none + /// CHECK-DAG: <<Mul:j\d+>> Mul [<<Par>>,<<Long>>] loop:none + /// CHECK-DAG: Return [<<Mul>>] loop:none + static long geoLongMulLastValue(long x) { + for (int i = 0; i < 10; i++) { + x *= 1081788608; + } + return x; + } + public static void main(String[] args) { expectEquals(10, earlyExitFirst(-1)); for (int i = 0; i <= 10; i++) { @@ -185,6 +260,42 @@ public class Main { expectEquals(-45, polynomialIntFromLong()); expectEquals(-45, polynomialInt()); + expectEquals(0, geoIntDivLastValue(0)); + expectEquals(0, geoIntDivLastValue(1)); + expectEquals(0, geoIntDivLastValue(2)); + expectEquals(0, geoIntDivLastValue(1081788608)); + expectEquals(0, geoIntDivLastValue(-1081788608)); + expectEquals(0, geoIntDivLastValue(2147483647)); + expectEquals(0, geoIntDivLastValue(-2147483648)); + + expectEquals( 0, geoIntMulLastValue(0)); + expectEquals( -194211840, geoIntMulLastValue(1)); + expectEquals( -388423680, geoIntMulLastValue(2)); + expectEquals(-1041498112, geoIntMulLastValue(1081788608)); + expectEquals( 1041498112, geoIntMulLastValue(-1081788608)); + expectEquals( 194211840, geoIntMulLastValue(2147483647)); + expectEquals( 0, geoIntMulLastValue(-2147483648)); + + expectEquals(0L, geoLongDivLastValue(0L)); + expectEquals(0L, geoLongDivLastValue(1L)); + expectEquals(0L, geoLongDivLastValue(2L)); + expectEquals(0L, geoLongDivLastValue(1081788608L)); + expectEquals(0L, geoLongDivLastValue(-1081788608L)); + expectEquals(0L, geoLongDivLastValue(2147483647L)); + expectEquals(0L, geoLongDivLastValue(-2147483648L)); + expectEquals(0L, geoLongDivLastValue(9223372036854775807L)); + expectEquals(0L, geoLongDivLastValue(-9223372036854775808L)); + + expectEquals( 0L, geoLongMulLastValue(0L)); + expectEquals(-8070450532247928832L, geoLongMulLastValue(1L)); + expectEquals( 2305843009213693952L, geoLongMulLastValue(2L)); + expectEquals( 0L, geoLongMulLastValue(1081788608L)); + expectEquals( 0L, geoLongMulLastValue(-1081788608L)); + expectEquals( 8070450532247928832L, geoLongMulLastValue(2147483647L)); + expectEquals( 0L, geoLongMulLastValue(-2147483648L)); + expectEquals( 8070450532247928832L, geoLongMulLastValue(9223372036854775807L)); + expectEquals( 0L, geoLongMulLastValue(-9223372036854775808L)); + System.out.println("passed"); } @@ -193,4 +304,10 @@ public class Main { throw new Error("Expected: " + expected + ", found: " + result); } } + + private static void expectEquals(long expected, long result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } } diff --git a/test/626-checker-arm64-scratch-register/src/Main.java b/test/626-checker-arm64-scratch-register/src/Main.java index aa211be33c..6dd4374116 100644 --- a/test/626-checker-arm64-scratch-register/src/Main.java +++ b/test/626-checker-arm64-scratch-register/src/Main.java @@ -95,8 +95,8 @@ public class Main { /// CHECK: str s1, [sp, #28] /// CHECK: ldr s1, [sp, #32] /// CHECK: str s31, [sp, #32] - /// CHECK: ldr w16, [sp, #20] - /// CHECK: str w16, [sp, #40] + /// CHECK: ldr s31, [sp, #20] + /// CHECK: str s31, [sp, #40] /// CHECK: str s12, [sp, #20] /// CHECK: fmov d12, d11 /// CHECK: fmov d11, d10 diff --git a/test/626-const-class-linking/clear_dex_cache_types.cc b/test/626-const-class-linking/clear_dex_cache_types.cc index b035896166..c0aedc199f 100644 --- a/test/626-const-class-linking/clear_dex_cache_types.cc +++ b/test/626-const-class-linking/clear_dex_cache_types.cc @@ -15,6 +15,9 @@ */ #include "jni.h" +#include "mirror/class-inl.h" +#include "mirror/class_loader.h" +#include "mirror/dex_cache-inl.h" #include "object_lock.h" #include "scoped_thread_state_change-inl.h" diff --git a/test/635-checker-arm64-volatile-load-cc/expected.txt b/test/635-checker-arm64-volatile-load-cc/expected.txt new file mode 100644 index 0000000000..b0aad4deb5 --- /dev/null +++ b/test/635-checker-arm64-volatile-load-cc/expected.txt @@ -0,0 +1 @@ +passed diff --git a/test/635-checker-arm64-volatile-load-cc/info.txt b/test/635-checker-arm64-volatile-load-cc/info.txt new file mode 100644 index 0000000000..5d67df4a19 --- /dev/null +++ b/test/635-checker-arm64-volatile-load-cc/info.txt @@ -0,0 +1,3 @@ +Regression test checking that the VIXL ARM64 scratch register pool is +not exhausted when generating a volatile field load with a large +offset with (Baker) read barriers (b/34726333). diff --git a/test/635-checker-arm64-volatile-load-cc/src/Main.java b/test/635-checker-arm64-volatile-load-cc/src/Main.java new file mode 100644 index 0000000000..6a26e940ac --- /dev/null +++ b/test/635-checker-arm64-volatile-load-cc/src/Main.java @@ -0,0 +1,284 @@ +/* + * Copyright (C) 2017 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. + */ + +public class Main { + + static volatile Object s000, s001, s002, s003, s004, s005, s006, s007, s008, s009; + static volatile Object s010, s011, s012, s013, s014, s015, s016, s017, s018, s019; + static volatile Object s020, s021, s022, s023, s024, s025, s026, s027, s028, s029; + static volatile Object s030, s031, s032, s033, s034, s035, s036, s037, s038, s039; + static volatile Object s040, s041, s042, s043, s044, s045, s046, s047, s048, s049; + static volatile Object s050, s051, s052, s053, s054, s055, s056, s057, s058, s059; + static volatile Object s060, s061, s062, s063, s064, s065, s066, s067, s068, s069; + static volatile Object s070, s071, s072, s073, s074, s075, s076, s077, s078, s079; + static volatile Object s080, s081, s082, s083, s084, s085, s086, s087, s088, s089; + static volatile Object s090, s091, s092, s093, s094, s095, s096, s097, s098, s099; + + static volatile Object s100, s101, s102, s103, s104, s105, s106, s107, s108, s109; + static volatile Object s110, s111, s112, s113, s114, s115, s116, s117, s118, s119; + static volatile Object s120, s121, s122, s123, s124, s125, s126, s127, s128, s129; + static volatile Object s130, s131, s132, s133, s134, s135, s136, s137, s138, s139; + static volatile Object s140, s141, s142, s143, s144, s145, s146, s147, s148, s149; + static volatile Object s150, s151, s152, s153, s154, s155, s156, s157, s158, s159; + static volatile Object s160, s161, s162, s163, s164, s165, s166, s167, s168, s169; + static volatile Object s170, s171, s172, s173, s174, s175, s176, s177, s178, s179; + static volatile Object s180, s181, s182, s183, s184, s185, s186, s187, s188, s189; + static volatile Object s190, s191, s192, s193, s194, s195, s196, s197, s198, s199; + + static volatile Object s200, s201, s202, s203, s204, s205, s206, s207, s208, s209; + static volatile Object s210, s211, s212, s213, s214, s215, s216, s217, s218, s219; + static volatile Object s220, s221, s222, s223, s224, s225, s226, s227, s228, s229; + static volatile Object s230, s231, s232, s233, s234, s235, s236, s237, s238, s239; + static volatile Object s240, s241, s242, s243, s244, s245, s246, s247, s248, s249; + static volatile Object s250, s251, s252, s253, s254, s255, s256, s257, s258, s259; + static volatile Object s260, s261, s262, s263, s264, s265, s266, s267, s268, s269; + static volatile Object s270, s271, s272, s273, s274, s275, s276, s277, s278, s279; + static volatile Object s280, s281, s282, s283, s284, s285, s286, s287, s288, s289; + static volatile Object s290, s291, s292, s293, s294, s295, s296, s297, s298, s299; + + static volatile Object s300, s301, s302, s303, s304, s305, s306, s307, s308, s309; + static volatile Object s310, s311, s312, s313, s314, s315, s316, s317, s318, s319; + static volatile Object s320, s321, s322, s323, s324, s325, s326, s327, s328, s329; + static volatile Object s330, s331, s332, s333, s334, s335, s336, s337, s338, s339; + static volatile Object s340, s341, s342, s343, s344, s345, s346, s347, s348, s349; + static volatile Object s350, s351, s352, s353, s354, s355, s356, s357, s358, s359; + static volatile Object s360, s361, s362, s363, s364, s365, s366, s367, s368, s369; + static volatile Object s370, s371, s372, s373, s374, s375, s376, s377, s378, s379; + static volatile Object s380, s381, s382, s383, s384, s385, s386, s387, s388, s389; + static volatile Object s390, s391, s392, s393, s394, s395, s396, s397, s398, s399; + + static volatile Object s400, s401, s402, s403, s404, s405, s406, s407, s408, s409; + static volatile Object s410, s411, s412, s413, s414, s415, s416, s417, s418, s419; + static volatile Object s420, s421, s422, s423, s424, s425, s426, s427, s428, s429; + static volatile Object s430, s431, s432, s433, s434, s435, s436, s437, s438, s439; + static volatile Object s440, s441, s442, s443, s444, s445, s446, s447, s448, s449; + static volatile Object s450, s451, s452, s453, s454, s455, s456, s457, s458, s459; + static volatile Object s460, s461, s462, s463, s464, s465, s466, s467, s468, s469; + static volatile Object s470, s471, s472, s473, s474, s475, s476, s477, s478, s479; + static volatile Object s480, s481, s482, s483, s484, s485, s486, s487, s488, s489; + static volatile Object s490, s491, s492, s493, s494, s495, s496, s497, s498, s499; + + static volatile Object s500, s501, s502, s503, s504, s505, s506, s507, s508, s509; + static volatile Object s510, s511, s512, s513, s514, s515, s516, s517, s518, s519; + static volatile Object s520, s521, s522, s523, s524, s525, s526, s527, s528, s529; + static volatile Object s530, s531, s532, s533, s534, s535, s536, s537, s538, s539; + static volatile Object s540, s541, s542, s543, s544, s545, s546, s547, s548, s549; + static volatile Object s550, s551, s552, s553, s554, s555, s556, s557, s558, s559; + static volatile Object s560, s561, s562, s563, s564, s565, s566, s567, s568, s569; + static volatile Object s570, s571, s572, s573, s574, s575, s576, s577, s578, s579; + static volatile Object s580, s581, s582, s583, s584, s585, s586, s587, s588, s589; + static volatile Object s590, s591, s592, s593, s594, s595, s596, s597, s598, s599; + + static volatile Object s600, s601, s602, s603, s604, s605, s606, s607, s608, s609; + static volatile Object s610, s611, s612, s613, s614, s615, s616, s617, s618, s619; + static volatile Object s620, s621, s622, s623, s624, s625, s626, s627, s628, s629; + static volatile Object s630, s631, s632, s633, s634, s635, s636, s637, s638, s639; + static volatile Object s640, s641, s642, s643, s644, s645, s646, s647, s648, s649; + static volatile Object s650, s651, s652, s653, s654, s655, s656, s657, s658, s659; + static volatile Object s660, s661, s662, s663, s664, s665, s666, s667, s668, s669; + static volatile Object s670, s671, s672, s673, s674, s675, s676, s677, s678, s679; + static volatile Object s680, s681, s682, s683, s684, s685, s686, s687, s688, s689; + static volatile Object s690, s691, s692, s693, s694, s695, s696, s697, s698, s699; + + static volatile Object s700, s701, s702, s703, s704, s705, s706, s707, s708, s709; + static volatile Object s710, s711, s712, s713, s714, s715, s716, s717, s718, s719; + static volatile Object s720, s721, s722, s723, s724, s725, s726, s727, s728, s729; + static volatile Object s730, s731, s732, s733, s734, s735, s736, s737, s738, s739; + static volatile Object s740, s741, s742, s743, s744, s745, s746, s747, s748, s749; + static volatile Object s750, s751, s752, s753, s754, s755, s756, s757, s758, s759; + static volatile Object s760, s761, s762, s763, s764, s765, s766, s767, s768, s769; + static volatile Object s770, s771, s772, s773, s774, s775, s776, s777, s778, s779; + static volatile Object s780, s781, s782, s783, s784, s785, s786, s787, s788, s789; + static volatile Object s790, s791, s792, s793, s794, s795, s796, s797, s798, s799; + + static volatile Object s800, s801, s802, s803, s804, s805, s806, s807, s808, s809; + static volatile Object s810, s811, s812, s813, s814, s815, s816, s817, s818, s819; + static volatile Object s820, s821, s822, s823, s824, s825, s826, s827, s828, s829; + static volatile Object s830, s831, s832, s833, s834, s835, s836, s837, s838, s839; + static volatile Object s840, s841, s842, s843, s844, s845, s846, s847, s848, s849; + static volatile Object s850, s851, s852, s853, s854, s855, s856, s857, s858, s859; + static volatile Object s860, s861, s862, s863, s864, s865, s866, s867, s868, s869; + static volatile Object s870, s871, s872, s873, s874, s875, s876, s877, s878, s879; + static volatile Object s880, s881, s882, s883, s884, s885, s886, s887, s888, s889; + static volatile Object s890, s891, s892, s893, s894, s895, s896, s897, s898, s899; + + static volatile Object s900, s901, s902, s903, s904, s905, s906, s907, s908, s909; + static volatile Object s910, s911, s912, s913, s914, s915, s916, s917, s918, s919; + static volatile Object s920, s921, s922, s923, s924, s925, s926, s927, s928, s929; + static volatile Object s930, s931, s932, s933, s934, s935, s936, s937, s938, s939; + static volatile Object s940, s941, s942, s943, s944, s945, s946, s947, s948, s949; + static volatile Object s950, s951, s952, s953, s954, s955, s956, s957, s958, s959; + static volatile Object s960, s961, s962, s963, s964, s965, s966, s967, s968, s969; + static volatile Object s970, s971, s972, s973, s974, s975, s976, s977, s978, s979; + static volatile Object s980, s981, s982, s983, s984, s985, s986, s987, s988, s989; + static volatile Object s990, s991, s992, s993, s994, s995, s996, s997, s998, s999; + + + volatile Object i0000, i0001, i0002, i0003, i0004, i0005, i0006, i0007, i0008, i0009; + volatile Object i0010, i0011, i0012, i0013, i0014, i0015, i0016, i0017, i0018, i0019; + volatile Object i0020, i0021, i0022, i0023, i0024, i0025, i0026, i0027, i0028, i0029; + volatile Object i0030, i0031, i0032, i0033, i0034, i0035, i0036, i0037, i0038, i0039; + volatile Object i0040, i0041, i0042, i0043, i0044, i0045, i0046, i0047, i0048, i0049; + volatile Object i0050, i0051, i0052, i0053, i0054, i0055, i0056, i0057, i0058, i0059; + volatile Object i0060, i0061, i0062, i0063, i0064, i0065, i0066, i0067, i0068, i0069; + volatile Object i0070, i0071, i0072, i0073, i0074, i0075, i0076, i0077, i0078, i0079; + volatile Object i0080, i0081, i0082, i0083, i0084, i0085, i0086, i0087, i0088, i0089; + volatile Object i0090, i0091, i0092, i0093, i0094, i0095, i0096, i0097, i0098, i0099; + + volatile Object i0100, i0101, i0102, i0103, i0104, i0105, i0106, i0107, i0108, i0109; + volatile Object i0110, i0111, i0112, i0113, i0114, i0115, i0116, i0117, i0118, i0119; + volatile Object i0120, i0121, i0122, i0123, i0124, i0125, i0126, i0127, i0128, i0129; + volatile Object i0130, i0131, i0132, i0133, i0134, i0135, i0136, i0137, i0138, i0139; + volatile Object i0140, i0141, i0142, i0143, i0144, i0145, i0146, i0147, i0148, i0149; + volatile Object i0150, i0151, i0152, i0153, i0154, i0155, i0156, i0157, i0158, i0159; + volatile Object i0160, i0161, i0162, i0163, i0164, i0165, i0166, i0167, i0168, i0169; + volatile Object i0170, i0171, i0172, i0173, i0174, i0175, i0176, i0177, i0178, i0179; + volatile Object i0180, i0181, i0182, i0183, i0184, i0185, i0186, i0187, i0188, i0189; + volatile Object i0190, i0191, i0192, i0193, i0194, i0195, i0196, i0197, i0198, i0199; + + volatile Object i0200, i0201, i0202, i0203, i0204, i0205, i0206, i0207, i0208, i0209; + volatile Object i0210, i0211, i0212, i0213, i0214, i0215, i0216, i0217, i0218, i0219; + volatile Object i0220, i0221, i0222, i0223, i0224, i0225, i0226, i0227, i0228, i0229; + volatile Object i0230, i0231, i0232, i0233, i0234, i0235, i0236, i0237, i0238, i0239; + volatile Object i0240, i0241, i0242, i0243, i0244, i0245, i0246, i0247, i0248, i0249; + volatile Object i0250, i0251, i0252, i0253, i0254, i0255, i0256, i0257, i0258, i0259; + volatile Object i0260, i0261, i0262, i0263, i0264, i0265, i0266, i0267, i0268, i0269; + volatile Object i0270, i0271, i0272, i0273, i0274, i0275, i0276, i0277, i0278, i0279; + volatile Object i0280, i0281, i0282, i0283, i0284, i0285, i0286, i0287, i0288, i0289; + volatile Object i0290, i0291, i0292, i0293, i0294, i0295, i0296, i0297, i0298, i0299; + + volatile Object i0300, i0301, i0302, i0303, i0304, i0305, i0306, i0307, i0308, i0309; + volatile Object i0310, i0311, i0312, i0313, i0314, i0315, i0316, i0317, i0318, i0319; + volatile Object i0320, i0321, i0322, i0323, i0324, i0325, i0326, i0327, i0328, i0329; + volatile Object i0330, i0331, i0332, i0333, i0334, i0335, i0336, i0337, i0338, i0339; + volatile Object i0340, i0341, i0342, i0343, i0344, i0345, i0346, i0347, i0348, i0349; + volatile Object i0350, i0351, i0352, i0353, i0354, i0355, i0356, i0357, i0358, i0359; + volatile Object i0360, i0361, i0362, i0363, i0364, i0365, i0366, i0367, i0368, i0369; + volatile Object i0370, i0371, i0372, i0373, i0374, i0375, i0376, i0377, i0378, i0379; + volatile Object i0380, i0381, i0382, i0383, i0384, i0385, i0386, i0387, i0388, i0389; + volatile Object i0390, i0391, i0392, i0393, i0394, i0395, i0396, i0397, i0398, i0399; + + volatile Object i0400, i0401, i0402, i0403, i0404, i0405, i0406, i0407, i0408, i0409; + volatile Object i0410, i0411, i0412, i0413, i0414, i0415, i0416, i0417, i0418, i0419; + volatile Object i0420, i0421, i0422, i0423, i0424, i0425, i0426, i0427, i0428, i0429; + volatile Object i0430, i0431, i0432, i0433, i0434, i0435, i0436, i0437, i0438, i0439; + volatile Object i0440, i0441, i0442, i0443, i0444, i0445, i0446, i0447, i0448, i0449; + volatile Object i0450, i0451, i0452, i0453, i0454, i0455, i0456, i0457, i0458, i0459; + volatile Object i0460, i0461, i0462, i0463, i0464, i0465, i0466, i0467, i0468, i0469; + volatile Object i0470, i0471, i0472, i0473, i0474, i0475, i0476, i0477, i0478, i0479; + volatile Object i0480, i0481, i0482, i0483, i0484, i0485, i0486, i0487, i0488, i0489; + volatile Object i0490, i0491, i0492, i0493, i0494, i0495, i0496, i0497, i0498, i0499; + + volatile Object i0500, i0501, i0502, i0503, i0504, i0505, i0506, i0507, i0508, i0509; + volatile Object i0510, i0511, i0512, i0513, i0514, i0515, i0516, i0517, i0518, i0519; + volatile Object i0520, i0521, i0522, i0523, i0524, i0525, i0526, i0527, i0528, i0529; + volatile Object i0530, i0531, i0532, i0533, i0534, i0535, i0536, i0537, i0538, i0539; + volatile Object i0540, i0541, i0542, i0543, i0544, i0545, i0546, i0547, i0548, i0549; + volatile Object i0550, i0551, i0552, i0553, i0554, i0555, i0556, i0557, i0558, i0559; + volatile Object i0560, i0561, i0562, i0563, i0564, i0565, i0566, i0567, i0568, i0569; + volatile Object i0570, i0571, i0572, i0573, i0574, i0575, i0576, i0577, i0578, i0579; + volatile Object i0580, i0581, i0582, i0583, i0584, i0585, i0586, i0587, i0588, i0589; + volatile Object i0590, i0591, i0592, i0593, i0594, i0595, i0596, i0597, i0598, i0599; + + volatile Object i0600, i0601, i0602, i0603, i0604, i0605, i0606, i0607, i0608, i0609; + volatile Object i0610, i0611, i0612, i0613, i0614, i0615, i0616, i0617, i0618, i0619; + volatile Object i0620, i0621, i0622, i0623, i0624, i0625, i0626, i0627, i0628, i0629; + volatile Object i0630, i0631, i0632, i0633, i0634, i0635, i0636, i0637, i0638, i0639; + volatile Object i0640, i0641, i0642, i0643, i0644, i0645, i0646, i0647, i0648, i0649; + volatile Object i0650, i0651, i0652, i0653, i0654, i0655, i0656, i0657, i0658, i0659; + volatile Object i0660, i0661, i0662, i0663, i0664, i0665, i0666, i0667, i0668, i0669; + volatile Object i0670, i0671, i0672, i0673, i0674, i0675, i0676, i0677, i0678, i0679; + volatile Object i0680, i0681, i0682, i0683, i0684, i0685, i0686, i0687, i0688, i0689; + volatile Object i0690, i0691, i0692, i0693, i0694, i0695, i0696, i0697, i0698, i0699; + + volatile Object i0700, i0701, i0702, i0703, i0704, i0705, i0706, i0707, i0708, i0709; + volatile Object i0710, i0711, i0712, i0713, i0714, i0715, i0716, i0717, i0718, i0719; + volatile Object i0720, i0721, i0722, i0723, i0724, i0725, i0726, i0727, i0728, i0729; + volatile Object i0730, i0731, i0732, i0733, i0734, i0735, i0736, i0737, i0738, i0739; + volatile Object i0740, i0741, i0742, i0743, i0744, i0745, i0746, i0747, i0748, i0749; + volatile Object i0750, i0751, i0752, i0753, i0754, i0755, i0756, i0757, i0758, i0759; + volatile Object i0760, i0761, i0762, i0763, i0764, i0765, i0766, i0767, i0768, i0769; + volatile Object i0770, i0771, i0772, i0773, i0774, i0775, i0776, i0777, i0778, i0779; + volatile Object i0780, i0781, i0782, i0783, i0784, i0785, i0786, i0787, i0788, i0789; + volatile Object i0790, i0791, i0792, i0793, i0794, i0795, i0796, i0797, i0798, i0799; + + volatile Object i0800, i0801, i0802, i0803, i0804, i0805, i0806, i0807, i0808, i0809; + volatile Object i0810, i0811, i0812, i0813, i0814, i0815, i0816, i0817, i0818, i0819; + volatile Object i0820, i0821, i0822, i0823, i0824, i0825, i0826, i0827, i0828, i0829; + volatile Object i0830, i0831, i0832, i0833, i0834, i0835, i0836, i0837, i0838, i0839; + volatile Object i0840, i0841, i0842, i0843, i0844, i0845, i0846, i0847, i0848, i0849; + volatile Object i0850, i0851, i0852, i0853, i0854, i0855, i0856, i0857, i0858, i0859; + volatile Object i0860, i0861, i0862, i0863, i0864, i0865, i0866, i0867, i0868, i0869; + volatile Object i0870, i0871, i0872, i0873, i0874, i0875, i0876, i0877, i0878, i0879; + volatile Object i0880, i0881, i0882, i0883, i0884, i0885, i0886, i0887, i0888, i0889; + volatile Object i0890, i0891, i0892, i0893, i0894, i0895, i0896, i0897, i0898, i0899; + + volatile Object i0900, i0901, i0902, i0903, i0904, i0905, i0906, i0907, i0908, i0909; + volatile Object i0910, i0911, i0912, i0913, i0914, i0915, i0916, i0917, i0918, i0919; + volatile Object i0920, i0921, i0922, i0923, i0924, i0925, i0926, i0927, i0928, i0929; + volatile Object i0930, i0931, i0932, i0933, i0934, i0935, i0936, i0937, i0938, i0939; + volatile Object i0940, i0941, i0942, i0943, i0944, i0945, i0946, i0947, i0948, i0949; + volatile Object i0950, i0951, i0952, i0953, i0954, i0955, i0956, i0957, i0958, i0959; + volatile Object i0960, i0961, i0962, i0963, i0964, i0965, i0966, i0967, i0968, i0969; + volatile Object i0970, i0971, i0972, i0973, i0974, i0975, i0976, i0977, i0978, i0979; + volatile Object i0980, i0981, i0982, i0983, i0984, i0985, i0986, i0987, i0988, i0989; + volatile Object i0990, i0991, i0992, i0993, i0994, i0995, i0996, i0997, i0998, i0999; + + volatile Object i1000, i1001, i1002, i1003, i1004, i1005, i1006, i1007, i1008, i1009; + volatile Object i1010, i1011, i1012, i1013, i1014, i1015, i1016, i1017, i1018, i1019; + volatile Object i1020, i1021, i1022, i1023, i1024, i1025, i1026, i1027, i1028, i1029; + volatile Object i1030, i1031, i1032, i1033, i1034, i1035, i1036, i1037, i1038, i1039; + volatile Object i1040, i1041, i1042, i1043, i1044, i1045, i1046, i1047, i1048, i1049; + volatile Object i1050, i1051, i1052, i1053, i1054, i1055, i1056, i1057, i1058, i1059; + volatile Object i1060, i1061, i1062, i1063, i1064, i1065, i1066, i1067, i1068, i1069; + volatile Object i1070, i1071, i1072, i1073, i1074, i1075, i1076, i1077, i1078, i1079; + volatile Object i1080, i1081, i1082, i1083, i1084, i1085, i1086, i1087, i1088, i1089; + volatile Object i1090, i1091, i1092, i1093, i1094, i1095, i1096, i1097, i1098, i1099; + + + // Note: ARM64, registers X16 and X17 are respectively IP0 and IP1, + // the scratch registers used by the VIXL AArch64 assembler (and to + // some extent, by ART's ARM64 code generator). + + /// CHECK-START-ARM64: void Main.testStaticVolatileFieldGetWithLargeOffset() disassembly (after) + /// CHECK: StaticFieldGet + /// CHECK: mov x17, #<<Offset:0x[0-9a-f]{4}>> + /// CHECK: add x16, {{x\d+}}, x17 + /// CHECK: ldar {{w\d+}}, [x16] + static void testStaticVolatileFieldGetWithLargeOffset() { + // The offset of this static field cannot be encoded as an immediate on ARM64. + Object s = s999; + } + + /// CHECK-START-ARM64: void Main.testInstanceVolatileFieldGetWithLargeOffset() disassembly (after) + /// CHECK: InstanceFieldGet + /// CHECK: mov x17, #<<Offset:0x[0-9a-f]{4}>> + /// CHECK: add x16, {{x\d+}}, x17 + /// CHECK: ldar {{w\d+}}, [x16] + void testInstanceVolatileFieldGetWithLargeOffset() { + // The offset of this instance field cannot be encoded as an immediate on ARM64. + Object i = i1029; + } + + + public static void main(String[] args) { + testStaticVolatileFieldGetWithLargeOffset(); + Main m = new Main(); + m.testInstanceVolatileFieldGetWithLargeOffset(); + System.out.println("passed"); + } + +} diff --git a/test/636-wrong-static-access/expected.txt b/test/636-wrong-static-access/expected.txt new file mode 100644 index 0000000000..6a5618ebc6 --- /dev/null +++ b/test/636-wrong-static-access/expected.txt @@ -0,0 +1 @@ +JNI_OnLoad called diff --git a/test/636-wrong-static-access/info.txt b/test/636-wrong-static-access/info.txt new file mode 100644 index 0000000000..184d858cb9 --- /dev/null +++ b/test/636-wrong-static-access/info.txt @@ -0,0 +1,2 @@ +Test that the compiler checks if a resolved field is +of the expected static/instance kind. diff --git a/test/636-wrong-static-access/run b/test/636-wrong-static-access/run new file mode 100755 index 0000000000..5e999209b8 --- /dev/null +++ b/test/636-wrong-static-access/run @@ -0,0 +1,20 @@ +#!/bin/bash +# +# Copyright (C) 2017 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. + +# Make verification soft fail, to ensure the verifier does not flag +# the method we want to compile as "non-compilable" because it sees +# the method will throw IncompatibleClassChangeError. +exec ${RUN} $@ --verify-soft-fail diff --git a/test/636-wrong-static-access/src-ex/Foo.java b/test/636-wrong-static-access/src-ex/Foo.java new file mode 100644 index 0000000000..9e3b7a74c8 --- /dev/null +++ b/test/636-wrong-static-access/src-ex/Foo.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2017 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. + */ + +public class Foo { + public static void doTest() { + // Execute foo once to make sure the dex cache will be updated. + try { + foo(); + throw new Error("Expected IncompatibleClassChangeError"); + } catch (IncompatibleClassChangeError e) { + // Expected. + } + Main.ensureJitCompiled(Foo.class, "foo"); + try { + foo(); + throw new Error("Expected IncompatibleClassChangeError"); + } catch (IncompatibleClassChangeError e) { + // Expected. + } + } + + public static void foo() { + System.out.println(Holder.field); + } +} diff --git a/test/636-wrong-static-access/src/Holder.java b/test/636-wrong-static-access/src/Holder.java new file mode 100644 index 0000000000..f3b1c5717c --- /dev/null +++ b/test/636-wrong-static-access/src/Holder.java @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2017 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. + */ + +public class Holder { + public static int field = 42; +} diff --git a/test/636-wrong-static-access/src/Main.java b/test/636-wrong-static-access/src/Main.java new file mode 100644 index 0000000000..bd8548e372 --- /dev/null +++ b/test/636-wrong-static-access/src/Main.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2017 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.lang.reflect.Constructor; +import java.lang.reflect.Method; + +public class Main { + static final String DEX_FILE = System.getenv("DEX_LOCATION") + "/636-wrong-static-access-ex.jar"; + + public static void main(String[] args) throws Exception { + System.loadLibrary(args[0]); + Class<?> pathClassLoader = Class.forName("dalvik.system.PathClassLoader"); + if (pathClassLoader == null) { + throw new AssertionError("Couldn't find path class loader class"); + } + Constructor<?> constructor = + pathClassLoader.getDeclaredConstructor(String.class, ClassLoader.class); + ClassLoader loader = (ClassLoader) constructor.newInstance( + DEX_FILE, ClassLoader.getSystemClassLoader()); + Class<?> foo = loader.loadClass("Foo"); + Method doTest = foo.getDeclaredMethod("doTest"); + doTest.invoke(null); + } + + public static native void ensureJitCompiled(Class<?> cls, String methodName); +} diff --git a/test/636-wrong-static-access/src2/Holder.java b/test/636-wrong-static-access/src2/Holder.java new file mode 100644 index 0000000000..a26da24319 --- /dev/null +++ b/test/636-wrong-static-access/src2/Holder.java @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2017 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. + */ + +public class Holder { + public int field = 42; +} diff --git a/test/706-checker-scheduler/expected.txt b/test/706-checker-scheduler/expected.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/706-checker-scheduler/expected.txt diff --git a/test/706-checker-scheduler/info.txt b/test/706-checker-scheduler/info.txt new file mode 100644 index 0000000000..b4ad9b4378 --- /dev/null +++ b/test/706-checker-scheduler/info.txt @@ -0,0 +1 @@ +Tests for HInstruction scheduler. diff --git a/test/706-checker-scheduler/src/Main.java b/test/706-checker-scheduler/src/Main.java new file mode 100644 index 0000000000..1721e4294e --- /dev/null +++ b/test/706-checker-scheduler/src/Main.java @@ -0,0 +1,82 @@ +/* + * 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. + */ + +public class Main { + + static int static_variable = 0; + + /// CHECK-START-ARM64: int Main.arrayAccess() scheduler (before) + /// CHECK: <<Const1:i\d+>> IntConstant 1 + /// CHECK: <<i0:i\d+>> Phi + /// CHECK: <<res0:i\d+>> Phi + /// CHECK: <<Array:i\d+>> IntermediateAddress + /// CHECK: <<ArrayGet1:i\d+>> ArrayGet [<<Array>>,<<i0>>] + /// CHECK: <<res1:i\d+>> Add [<<res0>>,<<ArrayGet1>>] + /// CHECK: <<i1:i\d+>> Add [<<i0>>,<<Const1>>] + /// CHECK: <<ArrayGet2:i\d+>> ArrayGet [<<Array>>,<<i1>>] + /// CHECK: Add [<<res1>>,<<ArrayGet2>>] + + /// CHECK-START-ARM64: int Main.arrayAccess() scheduler (after) + /// CHECK: <<Const1:i\d+>> IntConstant 1 + /// CHECK: <<i0:i\d+>> Phi + /// CHECK: <<res0:i\d+>> Phi + /// CHECK: <<Array:i\d+>> IntermediateAddress + /// CHECK: <<ArrayGet1:i\d+>> ArrayGet [<<Array>>,<<i0>>] + /// CHECK: <<i1:i\d+>> Add [<<i0>>,<<Const1>>] + /// CHECK: <<ArrayGet2:i\d+>> ArrayGet [<<Array>>,<<i1>>] + /// CHECK: <<res1:i\d+>> Add [<<res0>>,<<ArrayGet1>>] + /// CHECK: Add [<<res1>>,<<ArrayGet2>>] + + public static int arrayAccess() { + int res = 0; + int [] array = new int[10]; + for (int i = 0; i < 9; i++) { + res += array[i]; + res += array[i + 1]; + } + return res; + } + + /// CHECK-START-ARM64: int Main.intDiv(int) scheduler (before) + /// CHECK: Sub + /// CHECK: DivZeroCheck + /// CHECK: Div + /// CHECK: StaticFieldSet + + /// CHECK-START-ARM64: int Main.intDiv(int) scheduler (after) + /// CHECK: Sub + /// CHECK-NOT: StaticFieldSet + /// CHECK: DivZeroCheck + /// CHECK-NOT: Sub + /// CHECK: Div + public static int intDiv(int arg) { + int res = 0; + int tmp = arg; + for (int i = 1; i < arg; i++) { + tmp -= i; + res = res / i; // div-zero check barrier. + static_variable++; + } + res += tmp; + return res; + } + + public static void main(String[] args) { + if ((arrayAccess() + intDiv(10)) != -35) { + System.out.println("FAIL"); + } + } +} diff --git a/test/900-hello-plugin/run b/test/900-hello-plugin/run index 35b08715a1..50835f89af 100755 --- a/test/900-hello-plugin/run +++ b/test/900-hello-plugin/run @@ -18,7 +18,5 @@ plugin=libartagentd.so if [[ "$@" == *"-O"* ]]; then plugin=libartagent.so fi -./default-run "$@" --experimental agents \ - --experimental runtime-plugins \ - --runtime-option -agentpath:${plugin}=test_900 \ +./default-run "$@" --runtime-option -agentpath:${plugin}=test_900 \ --android-runtime-option -Xplugin:${plugin} diff --git a/test/901-hello-ti-agent/run b/test/901-hello-ti-agent/run index 4379349cb2..c6e62ae6cd 100755 --- a/test/901-hello-ti-agent/run +++ b/test/901-hello-ti-agent/run @@ -14,6 +14,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -./default-run "$@" --experimental agents \ - --experimental runtime-plugins \ - --jvmti +./default-run "$@" --jvmti diff --git a/test/902-hello-transformation/run b/test/902-hello-transformation/run index 4379349cb2..c6e62ae6cd 100755 --- a/test/902-hello-transformation/run +++ b/test/902-hello-transformation/run @@ -14,6 +14,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -./default-run "$@" --experimental agents \ - --experimental runtime-plugins \ - --jvmti +./default-run "$@" --jvmti diff --git a/test/903-hello-tagging/run b/test/903-hello-tagging/run index 4379349cb2..c6e62ae6cd 100755 --- a/test/903-hello-tagging/run +++ b/test/903-hello-tagging/run @@ -14,6 +14,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -./default-run "$@" --experimental agents \ - --experimental runtime-plugins \ - --jvmti +./default-run "$@" --jvmti diff --git a/test/904-object-allocation/run b/test/904-object-allocation/run index 4379349cb2..c6e62ae6cd 100755 --- a/test/904-object-allocation/run +++ b/test/904-object-allocation/run @@ -14,6 +14,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -./default-run "$@" --experimental agents \ - --experimental runtime-plugins \ - --jvmti +./default-run "$@" --jvmti diff --git a/test/905-object-free/run b/test/905-object-free/run index 4379349cb2..c6e62ae6cd 100755 --- a/test/905-object-free/run +++ b/test/905-object-free/run @@ -14,6 +14,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -./default-run "$@" --experimental agents \ - --experimental runtime-plugins \ - --jvmti +./default-run "$@" --jvmti diff --git a/test/906-iterate-heap/run b/test/906-iterate-heap/run index 4379349cb2..c6e62ae6cd 100755 --- a/test/906-iterate-heap/run +++ b/test/906-iterate-heap/run @@ -14,6 +14,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -./default-run "$@" --experimental agents \ - --experimental runtime-plugins \ - --jvmti +./default-run "$@" --jvmti diff --git a/test/907-get-loaded-classes/run b/test/907-get-loaded-classes/run index 4379349cb2..c6e62ae6cd 100755 --- a/test/907-get-loaded-classes/run +++ b/test/907-get-loaded-classes/run @@ -14,6 +14,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -./default-run "$@" --experimental agents \ - --experimental runtime-plugins \ - --jvmti +./default-run "$@" --jvmti diff --git a/test/908-gc-start-finish/gc_callbacks.cc b/test/908-gc-start-finish/gc_callbacks.cc index 59801ff648..8f96ee63ef 100644 --- a/test/908-gc-start-finish/gc_callbacks.cc +++ b/test/908-gc-start-finish/gc_callbacks.cc @@ -38,43 +38,32 @@ static void JNICALL GarbageCollectionStart(jvmtiEnv* ti_env ATTRIBUTE_UNUSED) { } extern "C" JNIEXPORT void JNICALL Java_Main_setupGcCallback( - JNIEnv* env ATTRIBUTE_UNUSED, jclass klass ATTRIBUTE_UNUSED) { + JNIEnv* env, jclass klass ATTRIBUTE_UNUSED) { jvmtiEventCallbacks callbacks; memset(&callbacks, 0, sizeof(jvmtiEventCallbacks)); callbacks.GarbageCollectionFinish = GarbageCollectionFinish; callbacks.GarbageCollectionStart = GarbageCollectionStart; jvmtiError ret = jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks)); - if (ret != JVMTI_ERROR_NONE) { - char* err; - jvmti_env->GetErrorName(ret, &err); - printf("Error setting callbacks: %s\n", err); - jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err)); - } + JvmtiErrorToException(env, ret); } -extern "C" JNIEXPORT void JNICALL Java_Main_enableGcTracking(JNIEnv* env ATTRIBUTE_UNUSED, +extern "C" JNIEXPORT void JNICALL Java_Main_enableGcTracking(JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jboolean enable) { jvmtiError ret = jvmti_env->SetEventNotificationMode( enable ? JVMTI_ENABLE : JVMTI_DISABLE, JVMTI_EVENT_GARBAGE_COLLECTION_START, nullptr); - if (ret != JVMTI_ERROR_NONE) { - char* err; - jvmti_env->GetErrorName(ret, &err); - printf("Error enabling/disabling gc callbacks: %s\n", err); - jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err)); + if (JvmtiErrorToException(env, ret)) { + return; } ret = jvmti_env->SetEventNotificationMode( enable ? JVMTI_ENABLE : JVMTI_DISABLE, JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, nullptr); - if (ret != JVMTI_ERROR_NONE) { - char* err; - jvmti_env->GetErrorName(ret, &err); - printf("Error enabling/disabling gc callbacks: %s\n", err); - jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err)); + if (JvmtiErrorToException(env, ret)) { + return; } } diff --git a/test/908-gc-start-finish/run b/test/908-gc-start-finish/run index 4379349cb2..c6e62ae6cd 100755 --- a/test/908-gc-start-finish/run +++ b/test/908-gc-start-finish/run @@ -14,6 +14,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -./default-run "$@" --experimental agents \ - --experimental runtime-plugins \ - --jvmti +./default-run "$@" --jvmti diff --git a/test/909-attach-agent/run b/test/909-attach-agent/run index 985341bd4f..4a2eb34a1d 100755 --- a/test/909-attach-agent/run +++ b/test/909-attach-agent/run @@ -21,17 +21,13 @@ if [[ "$@" == *"-O"* ]]; then plugin=libopenjdkjvmti.so fi -./default-run "$@" --experimental agents \ - --experimental runtime-plugins \ - --android-runtime-option -Xplugin:${plugin} \ - --android-runtime-option -Xfully-deoptable \ +./default-run "$@" --android-runtime-option -Xplugin:${plugin} \ + --android-runtime-option -Xcompiler-option \ + --android-runtime-option --debuggable \ --args agent:${agent}=909-attach-agent -./default-run "$@" --experimental agents \ - --experimental runtime-plugins \ - --android-runtime-option -Xfully-deoptable \ +./default-run "$@" --android-runtime-option -Xcompiler-option \ + --android-runtime-option --debuggable \ --args agent:${agent}=909-attach-agent -./default-run "$@" --experimental agents \ - --experimental runtime-plugins \ - --args agent:${agent}=909-attach-agent +./default-run "$@" --args agent:${agent}=909-attach-agent diff --git a/test/909-attach-agent/src/Main.java b/test/909-attach-agent/src/Main.java index 8a8a087458..569b89ad7d 100644 --- a/test/909-attach-agent/src/Main.java +++ b/test/909-attach-agent/src/Main.java @@ -19,7 +19,7 @@ import java.io.IOException; public class Main { public static void main(String[] args) { - System.out.println("Hello, world!"); + System.err.println("Hello, world!"); for(String a : args) { if(a.startsWith("agent:")) { String agent = a.substring(6); @@ -30,6 +30,6 @@ public class Main { } } } - System.out.println("Goodbye!"); + System.err.println("Goodbye!"); } } diff --git a/test/910-methods/run b/test/910-methods/run index 4379349cb2..c6e62ae6cd 100755 --- a/test/910-methods/run +++ b/test/910-methods/run @@ -14,6 +14,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -./default-run "$@" --experimental agents \ - --experimental runtime-plugins \ - --jvmti +./default-run "$@" --jvmti diff --git a/test/911-get-stack-trace/run b/test/911-get-stack-trace/run index 4379349cb2..c6e62ae6cd 100755 --- a/test/911-get-stack-trace/run +++ b/test/911-get-stack-trace/run @@ -14,6 +14,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -./default-run "$@" --experimental agents \ - --experimental runtime-plugins \ - --jvmti +./default-run "$@" --jvmti diff --git a/test/911-get-stack-trace/src/PrintThread.java b/test/911-get-stack-trace/src/PrintThread.java index 97815ccad9..136fd80d40 100644 --- a/test/911-get-stack-trace/src/PrintThread.java +++ b/test/911-get-stack-trace/src/PrintThread.java @@ -44,6 +44,9 @@ public class PrintThread { if (name.contains("Daemon")) { // Do not print daemon stacks, as they're non-deterministic. stackSerialization = "<not printed>"; + } else if (name.startsWith("Jit thread pool worker")) { + // Skip JIT thread pool. It may or may not be there depending on configuration. + continue; } else { StringBuilder sb = new StringBuilder(); for (String[] stackElement : (String[][])stackInfo[1]) { diff --git a/test/912-classes/expected.txt b/test/912-classes/expected.txt index d0b77a4bae..328216b324 100644 --- a/test/912-classes/expected.txt +++ b/test/912-classes/expected.txt @@ -29,7 +29,7 @@ int 100000 class [Ljava.lang.String; 10000 class java.lang.Object 111 class Main$TestForNonInit 11 -class Main$TestForInitFail 1001 +class Main$TestForInitFail 1011 int [] class [Ljava.lang.String; [] class java.lang.Object [] diff --git a/test/912-classes/run b/test/912-classes/run index 20dfc4b767..f24db40cb0 100755 --- a/test/912-classes/run +++ b/test/912-classes/run @@ -18,7 +18,5 @@ # In certain configurations, the app images may be valid even in a new classloader. Turn off # app images to avoid the issue. -./default-run "$@" --experimental agents \ - --experimental runtime-plugins \ - --jvmti \ +./default-run "$@" --jvmti \ --no-app-image diff --git a/test/913-heaps/run b/test/913-heaps/run index 4379349cb2..c6e62ae6cd 100755 --- a/test/913-heaps/run +++ b/test/913-heaps/run @@ -14,6 +14,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -./default-run "$@" --experimental agents \ - --experimental runtime-plugins \ - --jvmti +./default-run "$@" --jvmti diff --git a/test/914-hello-obsolescence/run b/test/914-hello-obsolescence/run index 4379349cb2..c6e62ae6cd 100755 --- a/test/914-hello-obsolescence/run +++ b/test/914-hello-obsolescence/run @@ -14,6 +14,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -./default-run "$@" --experimental agents \ - --experimental runtime-plugins \ - --jvmti +./default-run "$@" --jvmti diff --git a/test/915-obsolete-2/run b/test/915-obsolete-2/run index 4379349cb2..c6e62ae6cd 100755 --- a/test/915-obsolete-2/run +++ b/test/915-obsolete-2/run @@ -14,6 +14,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -./default-run "$@" --experimental agents \ - --experimental runtime-plugins \ - --jvmti +./default-run "$@" --jvmti diff --git a/test/916-obsolete-jit/run b/test/916-obsolete-jit/run index 9056211284..b6d406fd99 100755 --- a/test/916-obsolete-jit/run +++ b/test/916-obsolete-jit/run @@ -21,7 +21,5 @@ if [[ "$@" == *"--jit"* ]]; then else other_args="--jit" fi -./default-run "$@" --experimental agents \ - --experimental runtime-plugins \ - ${other_args} \ +./default-run "$@" ${other_args} \ --jvmti diff --git a/test/916-obsolete-jit/src/Main.java b/test/916-obsolete-jit/src/Main.java index 1b03200ba5..2b3296f1f2 100644 --- a/test/916-obsolete-jit/src/Main.java +++ b/test/916-obsolete-jit/src/Main.java @@ -116,37 +116,27 @@ public class Main { doTest(new Transform(), new TestWatcher()); } - // TODO Workaround to (1) inability to ensure that current_method is not put into a register by - // the JIT and/or (2) inability to deoptimize frames near runtime functions. - // TODO Fix one/both of these issues. - public static void doCall(Runnable r) { - r.run(); - } - private static boolean interpreting = true; private static boolean retry = false; public static void doTest(Transform t, TestWatcher w) { // Get the methods that need to be optimized. Method say_hi_method; - Method do_call_method; // Figure out if we can even JIT at all. final boolean has_jit = hasJit(); try { say_hi_method = Transform.class.getDeclaredMethod( "sayHi", Runnable.class, Consumer.class); - do_call_method = Main.class.getDeclaredMethod("doCall", 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 a bad stack. + // set the retry boolean to true if the stack does not have a JIT-compiled sayHi entry. This can + // only happen if the method gets GC'd. Runnable do_redefinition = () -> { - if (has_jit && - (Main.isInterpretedFunction(say_hi_method, true) || - Main.isInterpretedFunction(do_call_method, false))) { + if (has_jit && Main.isInterpretedFunction(say_hi_method, true)) { // Try again. We are not running the right jitted methods/cannot redefine them now. retry = true; } else { @@ -161,7 +151,6 @@ public class Main { do { // Run ensureJitCompiled here since it might get GCd ensureJitCompiled(Transform.class, "sayHi"); - ensureJitCompiled(Main.class, "doCall"); // Clear output. w.clear(); // Try and redefine. diff --git a/test/916-obsolete-jit/src/Transform.java b/test/916-obsolete-jit/src/Transform.java index f4dcf09dc6..9c9adbc22d 100644 --- a/test/916-obsolete-jit/src/Transform.java +++ b/test/916-obsolete-jit/src/Transform.java @@ -29,13 +29,7 @@ class Transform { reporter.accept("Pre Start private method call"); Start(reporter); reporter.accept("Post Start private method call"); - // TODO Revisit with b/33616143 - // TODO Uncomment this once either b/33630159 or b/33616143 are resolved. - // r.run(); - // TODO This doCall function is a very temporary fix until we get either deoptimization near - // runtime frames working, forcing current method to be always read from the stack or both - // working. - Main.doCall(r); + r.run(); reporter.accept("Pre Finish private method call"); Finish(reporter); reporter.accept("Post Finish private method call"); diff --git a/test/917-fields-transformation/run b/test/917-fields-transformation/run index 4379349cb2..c6e62ae6cd 100755 --- a/test/917-fields-transformation/run +++ b/test/917-fields-transformation/run @@ -14,6 +14,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -./default-run "$@" --experimental agents \ - --experimental runtime-plugins \ - --jvmti +./default-run "$@" --jvmti diff --git a/test/918-fields/run b/test/918-fields/run index 4379349cb2..c6e62ae6cd 100755 --- a/test/918-fields/run +++ b/test/918-fields/run @@ -14,6 +14,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -./default-run "$@" --experimental agents \ - --experimental runtime-plugins \ - --jvmti +./default-run "$@" --jvmti diff --git a/test/919-obsolete-fields/run b/test/919-obsolete-fields/run index 4379349cb2..c6e62ae6cd 100755 --- a/test/919-obsolete-fields/run +++ b/test/919-obsolete-fields/run @@ -14,6 +14,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -./default-run "$@" --experimental agents \ - --experimental runtime-plugins \ - --jvmti +./default-run "$@" --jvmti diff --git a/test/919-obsolete-fields/src/Main.java b/test/919-obsolete-fields/src/Main.java index 1d893f125a..ffb9897236 100644 --- a/test/919-obsolete-fields/src/Main.java +++ b/test/919-obsolete-fields/src/Main.java @@ -120,13 +120,6 @@ public class Main { doTest(new Transform(w), w); } - // TODO Workaround to (1) inability to ensure that current_method is not put into a register by - // the JIT and/or (2) inability to deoptimize frames near runtime functions. - // TODO Fix one/both of these issues. - public static void doCall(Runnable r) { - r.run(); - } - private static boolean interpreting = true; private static boolean retry = false; diff --git a/test/919-obsolete-fields/src/Transform.java b/test/919-obsolete-fields/src/Transform.java index abd1d19b66..c8e3cbd934 100644 --- a/test/919-obsolete-fields/src/Transform.java +++ b/test/919-obsolete-fields/src/Transform.java @@ -34,12 +34,7 @@ class Transform { reporter.accept("Pre Start private method call"); Start(); reporter.accept("Post Start private method call"); - // TODO Revist with b/33616143 - // TODO Uncomment this - // r.run(); - // TODO This is a very temporary fix until we get either deoptimization near runtime frames - // working, forcing current method to be always read from the stack or both working. - Main.doCall(r); + r.run(); reporter.accept("Pre Finish private method call"); Finish(); reporter.accept("Post Finish private method call"); diff --git a/test/920-objects/run b/test/920-objects/run index 4379349cb2..c6e62ae6cd 100755 --- a/test/920-objects/run +++ b/test/920-objects/run @@ -14,6 +14,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -./default-run "$@" --experimental agents \ - --experimental runtime-plugins \ - --jvmti +./default-run "$@" --jvmti diff --git a/test/921-hello-failure/expected.txt b/test/921-hello-failure/expected.txt index 9615e6b33d..e9b6a20cd6 100644 --- a/test/921-hello-failure/expected.txt +++ b/test/921-hello-failure/expected.txt @@ -29,3 +29,21 @@ hello2 - MultiRetrans Transformation error : java.lang.Exception(Failed to retransform classes <LTransform;, LTransform2;> due to JVMTI_ERROR_NAMES_DONT_MATCH) hello - MultiRetrans hello2 - MultiRetrans +hello - NewMethod +Transformation error : java.lang.Exception(Failed to redefine class <LTransform;> due to JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_ADDED) +hello - NewMethod +hello2 - MissingMethod +Transformation error : java.lang.Exception(Failed to redefine class <LTransform3;> due to JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_DELETED) +hello2 - MissingMethod +hello - MethodChange +Transformation error : java.lang.Exception(Failed to redefine class <LTransform;> due to JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_MODIFIERS_CHANGED) +hello - MethodChange +hello - NewField +Transformation error : java.lang.Exception(Failed to redefine class <LTransform;> due to JVMTI_ERROR_UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED) +hello - NewField +hello there - MissingField +Transformation error : java.lang.Exception(Failed to redefine class <LTransform4;> due to JVMTI_ERROR_UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED) +hello there - MissingField +hello there again - FieldChange +Transformation error : java.lang.Exception(Failed to redefine class <LTransform4;> due to JVMTI_ERROR_UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED) +hello there again - FieldChange diff --git a/test/921-hello-failure/run b/test/921-hello-failure/run index 3ef4832da2..8be0ed4aed 100755 --- a/test/921-hello-failure/run +++ b/test/921-hello-failure/run @@ -15,6 +15,4 @@ # limitations under the License. -./default-run "$@" --experimental agents \ - --experimental runtime-plugins \ - --jvmti +./default-run "$@" --jvmti diff --git a/test/921-hello-failure/src/FieldChange.java b/test/921-hello-failure/src/FieldChange.java new file mode 100644 index 0000000000..cc2ea284d9 --- /dev/null +++ b/test/921-hello-failure/src/FieldChange.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2017 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; + +class FieldChange { + // The following is a base64 encoding of the following class. + // class Transform4 { + // private Object greeting; + // public Transform4(String hi) { } + // public void sayHi(String name) { + // throw new Error("Should not be called!"); + // } + // } + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAFwoABgAQBwARCAASCgACABMHABQHABUBAAhncmVldGluZwEAEkxqYXZhL2xhbmcv" + + "T2JqZWN0OwEABjxpbml0PgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEABENvZGUBAA9MaW5lTnVt" + + "YmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAA9UcmFuc2Zvcm00LmphdmEMAAkAFgEAD2ph" + + "dmEvbGFuZy9FcnJvcgEAFVNob3VsZCBub3QgYmUgY2FsbGVkIQwACQAKAQAKVHJhbnNmb3JtNAEA" + + "EGphdmEvbGFuZy9PYmplY3QBAAMoKVYAIAAFAAYAAAABAAIABwAIAAAAAgABAAkACgABAAsAAAAd" + + "AAEAAgAAAAUqtwABsQAAAAEADAAAAAYAAQAAAAMAAQANAAoAAQALAAAAIgADAAIAAAAKuwACWRID" + + "twAEvwAAAAEADAAAAAYAAQAAAAUAAQAOAAAAAgAP"); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQASXs5yszuhud+/w4q07495k9eO7Yb+l8u4AgAAcAAAAHhWNBIAAAAAAAAAABgCAAAM" + + "AAAAcAAAAAUAAACgAAAAAgAAALQAAAABAAAAzAAAAAQAAADUAAAAAQAAAPQAAACkAQAAFAEAAFYB" + + "AABeAQAAbAEAAH8BAACTAQAApwEAAL4BAADPAQAA0gEAANYBAADqAQAA9AEAAAEAAAACAAAAAwAA" + + "AAQAAAAHAAAABwAAAAQAAAAAAAAACAAAAAQAAABQAQAAAAACAAoAAAAAAAEAAAAAAAAAAQALAAAA" + + "AQABAAAAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAGAAAAAAAAAAcCAAAAAAAAAgACAAEAAAD7" + + "AQAABAAAAHAQAwAAAA4ABAACAAIAAAABAgAACQAAACIAAQAbAQUAAABwIAIAEAAnAAAAAQAAAAMA" + + "Bjxpbml0PgAMTFRyYW5zZm9ybTQ7ABFMamF2YS9sYW5nL0Vycm9yOwASTGphdmEvbGFuZy9PYmpl" + + "Y3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAFVNob3VsZCBub3QgYmUgY2FsbGVkIQAPVHJhbnNmb3Jt" + + "NC5qYXZhAAFWAAJWTAASZW1pdHRlcjogamFjay00LjIyAAhncmVldGluZwAFc2F5SGkAAwEABw4A" + + "BQEABw4AAAEBAQACAIGABJQCAQGsAgANAAAAAAAAAAEAAAAAAAAAAQAAAAwAAABwAAAAAgAAAAUA" + + "AACgAAAAAwAAAAIAAAC0AAAABAAAAAEAAADMAAAABQAAAAQAAADUAAAABgAAAAEAAAD0AAAAASAA" + + "AAIAAAAUAQAAARAAAAEAAABQAQAAAiAAAAwAAABWAQAAAyAAAAIAAAD7AQAAACAAAAEAAAAHAgAA" + + "ABAAAAEAAAAYAgAA"); + + public static void doTest(Transform4 t) { + t.sayHi("FieldChange"); + try { + Main.doCommonClassRedefinition(Transform4.class, CLASS_BYTES, DEX_BYTES); + } catch (Exception e) { + System.out.println( + "Transformation error : " + e.getClass().getName() + "(" + e.getMessage() + ")"); + } + t.sayHi("FieldChange"); + } +} diff --git a/test/921-hello-failure/src/Main.java b/test/921-hello-failure/src/Main.java index 67ca1e15d6..61d69e7396 100644 --- a/test/921-hello-failure/src/Main.java +++ b/test/921-hello-failure/src/Main.java @@ -25,6 +25,12 @@ public class Main { ReorderInterface.doTest(new Transform2()); MultiRedef.doTest(new Transform(), new Transform2()); MultiRetrans.doTest(new Transform(), new Transform2()); + NewMethod.doTest(new Transform()); + MissingMethod.doTest(new Transform3()); + MethodChange.doTest(new Transform()); + NewField.doTest(new Transform()); + MissingField.doTest(new Transform4("there")); + FieldChange.doTest(new Transform4("there again")); } // Transforms the class. This throws an exception if something goes wrong. diff --git a/test/921-hello-failure/src/MethodChange.java b/test/921-hello-failure/src/MethodChange.java new file mode 100644 index 0000000000..16f57788c8 --- /dev/null +++ b/test/921-hello-failure/src/MethodChange.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2017 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; + +class MethodChange { + // The following is a base64 encoding of the following class. + // class Transform { + // void sayHi(String name) { + // throw new Error("Should not be called!"); + // } + // } + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAFQoABgAPBwAQCAARCgACABIHABMHABQBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAP" + + "TGluZU51bWJlclRhYmxlAQAFc2F5SGkBABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBAApTb3VyY2VG" + + "aWxlAQAOVHJhbnNmb3JtLmphdmEMAAcACAEAD2phdmEvbGFuZy9FcnJvcgEAFVNob3VsZCBub3Qg" + + "YmUgY2FsbGVkIQwABwAMAQAJVHJhbnNmb3JtAQAQamF2YS9sYW5nL09iamVjdAAgAAUABgAAAAAA" + + "AgAAAAcACAABAAkAAAAdAAEAAQAAAAUqtwABsQAAAAEACgAAAAYAAQAAAAIAAAALAAwAAQAJAAAA" + + "IgADAAIAAAAKuwACWRIDtwAEvwAAAAEACgAAAAYAAQAAAAQAAQANAAAAAgAO"); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQCrV81cy4Q+YKMMMqc0bZEO5Y1X5u7irPeQAgAAcAAAAHhWNBIAAAAAAAAAAPwBAAAL" + + "AAAAcAAAAAUAAACcAAAAAgAAALAAAAAAAAAAAAAAAAQAAADIAAAAAQAAAOgAAACIAQAACAEAAEoB" + + "AABSAQAAXwEAAHIBAACGAQAAmgEAALEBAADBAQAAxAEAAMgBAADcAQAAAQAAAAIAAAADAAAABAAA" + + "AAcAAAAHAAAABAAAAAAAAAAIAAAABAAAAEQBAAAAAAAAAAAAAAAAAQAKAAAAAQABAAAAAAACAAAA" + + "AAAAAAAAAAAAAAAAAgAAAAAAAAAGAAAAAAAAAO4BAAAAAAAAAQABAAEAAADjAQAABAAAAHAQAwAA" + + "AA4ABAACAAIAAADoAQAACQAAACIAAQAbAQUAAABwIAIAEAAnAAAAAQAAAAMABjxpbml0PgALTFRy" + + "YW5zZm9ybTsAEUxqYXZhL2xhbmcvRXJyb3I7ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xh" + + "bmcvU3RyaW5nOwAVU2hvdWxkIG5vdCBiZSBjYWxsZWQhAA5UcmFuc2Zvcm0uamF2YQABVgACVkwA" + + "EmVtaXR0ZXI6IGphY2stNC4yNAAFc2F5SGkAAgAHDgAEAQAHDgAAAAEBAICABIgCAQCgAgwAAAAA" + + "AAAAAQAAAAAAAAABAAAACwAAAHAAAAACAAAABQAAAJwAAAADAAAAAgAAALAAAAAFAAAABAAAAMgA" + + "AAAGAAAAAQAAAOgAAAABIAAAAgAAAAgBAAABEAAAAQAAAEQBAAACIAAACwAAAEoBAAADIAAAAgAA" + + "AOMBAAAAIAAAAQAAAO4BAAAAEAAAAQAAAPwBAAA="); + + public static void doTest(Transform t) { + t.sayHi("MethodChange"); + try { + Main.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); + } catch (Exception e) { + System.out.println( + "Transformation error : " + e.getClass().getName() + "(" + e.getMessage() + ")"); + } + t.sayHi("MethodChange"); + } +} diff --git a/test/921-hello-failure/src/MissingField.java b/test/921-hello-failure/src/MissingField.java new file mode 100644 index 0000000000..2f643cc871 --- /dev/null +++ b/test/921-hello-failure/src/MissingField.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2017 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; + +class MissingField { + // The following is a base64 encoding of the following class. + // class Transform4 { + // public Transform4(String s) { } + // public void sayHi(String name) { + // throw new Error("Should not be called!"); + // } + // } + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAFQoABgAOBwAPCAAQCgACABEHABIHABMBAAY8aW5pdD4BABUoTGphdmEvbGFuZy9T" + + "dHJpbmc7KVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQAFc2F5SGkBAApTb3VyY2VGaWxlAQAP" + + "VHJhbnNmb3JtNC5qYXZhDAAHABQBAA9qYXZhL2xhbmcvRXJyb3IBABVTaG91bGQgbm90IGJlIGNh" + + "bGxlZCEMAAcACAEAClRyYW5zZm9ybTQBABBqYXZhL2xhbmcvT2JqZWN0AQADKClWACAABQAGAAAA" + + "AAACAAEABwAIAAEACQAAAB0AAQACAAAABSq3AAGxAAAAAQAKAAAABgABAAAAAgABAAsACAABAAkA" + + "AAAiAAMAAgAAAAq7AAJZEgO3AAS/AAAAAQAKAAAABgABAAAABAABAAwAAAACAA0="); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQDBVUVrMUEFx3lYkgJF54evq9vHvOUDZveUAgAAcAAAAHhWNBIAAAAAAAAAAAACAAAL" + + "AAAAcAAAAAUAAACcAAAAAgAAALAAAAAAAAAAAAAAAAQAAADIAAAAAQAAAOgAAACMAQAACAEAAEoB" + + "AABSAQAAYAEAAHMBAACHAQAAmwEAALIBAADDAQAAxgEAAMoBAADeAQAAAQAAAAIAAAADAAAABAAA" + + "AAcAAAAHAAAABAAAAAAAAAAIAAAABAAAAEQBAAAAAAEAAAAAAAAAAQAKAAAAAQABAAAAAAACAAAA" + + "AAAAAAAAAAAAAAAAAgAAAAAAAAAGAAAAAAAAAPEBAAAAAAAAAgACAAEAAADlAQAABAAAAHAQAwAA" + + "AA4ABAACAAIAAADrAQAACQAAACIAAQAbAQUAAABwIAIAEAAnAAAAAQAAAAMABjxpbml0PgAMTFRy" + + "YW5zZm9ybTQ7ABFMamF2YS9sYW5nL0Vycm9yOwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9s" + + "YW5nL1N0cmluZzsAFVNob3VsZCBub3QgYmUgY2FsbGVkIQAPVHJhbnNmb3JtNC5qYXZhAAFWAAJW" + + "TAASZW1pdHRlcjogamFjay00LjIyAAVzYXlIaQACAQAHDgAEAQAHDgAAAAEBAIGABIgCAQGgAgAM" + + "AAAAAAAAAAEAAAAAAAAAAQAAAAsAAABwAAAAAgAAAAUAAACcAAAAAwAAAAIAAACwAAAABQAAAAQA" + + "AADIAAAABgAAAAEAAADoAAAAASAAAAIAAAAIAQAAARAAAAEAAABEAQAAAiAAAAsAAABKAQAAAyAA" + + "AAIAAADlAQAAACAAAAEAAADxAQAAABAAAAEAAAAAAgAA"); + + public static void doTest(Transform4 t) { + t.sayHi("MissingField"); + try { + Main.doCommonClassRedefinition(Transform4.class, CLASS_BYTES, DEX_BYTES); + } catch (Exception e) { + System.out.println( + "Transformation error : " + e.getClass().getName() + "(" + e.getMessage() + ")"); + } + t.sayHi("MissingField"); + } +} diff --git a/test/921-hello-failure/src/MissingMethod.java b/test/921-hello-failure/src/MissingMethod.java new file mode 100644 index 0000000000..3f1925c9ad --- /dev/null +++ b/test/921-hello-failure/src/MissingMethod.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2017 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; + +class MissingMethod { + // The following is a base64 encoding of the following class. + // class Transform3 { + // public void sayHi(String name) { + // throw new Error("Should not be called!"); + // } + // } + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAFQoABgAPBwAQCAARCgACABIHABMHABQBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAP" + + "TGluZU51bWJlclRhYmxlAQAFc2F5SGkBABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBAApTb3VyY2VG" + + "aWxlAQAPVHJhbnNmb3JtMy5qYXZhDAAHAAgBAA9qYXZhL2xhbmcvRXJyb3IBABVTaG91bGQgbm90" + + "IGJlIGNhbGxlZCEMAAcADAEAClRyYW5zZm9ybTMBABBqYXZhL2xhbmcvT2JqZWN0ACAABQAGAAAA" + + "AAACAAAABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAAAgABAAsADAABAAkA" + + "AAAiAAMAAgAAAAq7AAJZEgO3AAS/AAAAAQAKAAAABgABAAAABAABAA0AAAACAA4="); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQDnVQvyn7XrwDiCC/SE55zBCtEqk4pzA2mUAgAAcAAAAHhWNBIAAAAAAAAAAAACAAAL" + + "AAAAcAAAAAUAAACcAAAAAgAAALAAAAAAAAAAAAAAAAQAAADIAAAAAQAAAOgAAACMAQAACAEAAEoB" + + "AABSAQAAYAEAAHMBAACHAQAAmwEAALIBAADDAQAAxgEAAMoBAADeAQAAAQAAAAIAAAADAAAABAAA" + + "AAcAAAAHAAAABAAAAAAAAAAIAAAABAAAAEQBAAAAAAAAAAAAAAAAAQAKAAAAAQABAAAAAAACAAAA" + + "AAAAAAAAAAAAAAAAAgAAAAAAAAAGAAAAAAAAAPABAAAAAAAAAQABAAEAAADlAQAABAAAAHAQAwAA" + + "AA4ABAACAAIAAADqAQAACQAAACIAAQAbAQUAAABwIAIAEAAnAAAAAQAAAAMABjxpbml0PgAMTFRy" + + "YW5zZm9ybTM7ABFMamF2YS9sYW5nL0Vycm9yOwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9s" + + "YW5nL1N0cmluZzsAFVNob3VsZCBub3QgYmUgY2FsbGVkIQAPVHJhbnNmb3JtMy5qYXZhAAFWAAJW" + + "TAASZW1pdHRlcjogamFjay00LjI0AAVzYXlIaQACAAcOAAQBAAcOAAAAAQEAgIAEiAIBAaACAAAM" + + "AAAAAAAAAAEAAAAAAAAAAQAAAAsAAABwAAAAAgAAAAUAAACcAAAAAwAAAAIAAACwAAAABQAAAAQA" + + "AADIAAAABgAAAAEAAADoAAAAASAAAAIAAAAIAQAAARAAAAEAAABEAQAAAiAAAAsAAABKAQAAAyAA" + + "AAIAAADlAQAAACAAAAEAAADwAQAAABAAAAEAAAAAAgAA"); + + public static void doTest(Transform3 t) { + t.sayHi("MissingMethod"); + try { + Main.doCommonClassRedefinition(Transform3.class, CLASS_BYTES, DEX_BYTES); + } catch (Exception e) { + System.out.println( + "Transformation error : " + e.getClass().getName() + "(" + e.getMessage() + ")"); + } + t.sayHi("MissingMethod"); + } +} diff --git a/test/921-hello-failure/src/NewField.java b/test/921-hello-failure/src/NewField.java new file mode 100644 index 0000000000..c85b79e824 --- /dev/null +++ b/test/921-hello-failure/src/NewField.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2017 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; + +class NewField { + // The following is a base64 encoding of the following class. + // class Transform { + // private Object field; + // public void sayHi(String name) { + // throw new Error("Should not be called!"); + // } + // } + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAFwoABgARBwASCAATCgACABQHABUHABYBAAVmaWVsZAEAEkxqYXZhL2xhbmcvT2Jq" + + "ZWN0OwEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAFShM" + + "amF2YS9sYW5nL1N0cmluZzspVgEAClNvdXJjZUZpbGUBAA5UcmFuc2Zvcm0uamF2YQwACQAKAQAP" + + "amF2YS9sYW5nL0Vycm9yAQAVU2hvdWxkIG5vdCBiZSBjYWxsZWQhDAAJAA4BAAlUcmFuc2Zvcm0B" + + "ABBqYXZhL2xhbmcvT2JqZWN0ACAABQAGAAAAAQACAAcACAAAAAIAAAAJAAoAAQALAAAAHQABAAEA" + + "AAAFKrcAAbEAAAABAAwAAAAGAAEAAAABAAEADQAOAAEACwAAACIAAwACAAAACrsAAlkSA7cABL8A" + + "AAABAAwAAAAGAAEAAAAEAAEADwAAAAIAEA=="); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQBNWknL2iyjim487p0EIH/8V5OjOeLgw5e0AgAAcAAAAHhWNBIAAAAAAAAAABQCAAAM" + + "AAAAcAAAAAUAAACgAAAAAgAAALQAAAABAAAAzAAAAAQAAADUAAAAAQAAAPQAAACgAQAAFAEAAFYB" + + "AABeAQAAawEAAH4BAACSAQAApgEAAL0BAADNAQAA0AEAANQBAADoAQAA7wEAAAEAAAACAAAAAwAA" + + "AAQAAAAHAAAABwAAAAQAAAAAAAAACAAAAAQAAABQAQAAAAACAAoAAAAAAAAAAAAAAAAAAQALAAAA" + + "AQABAAAAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAGAAAAAAAAAAECAAAAAAAAAQABAAEAAAD2" + + "AQAABAAAAHAQAwAAAA4ABAACAAIAAAD7AQAACQAAACIAAQAbAQUAAABwIAIAEAAnAAAAAQAAAAMA" + + "Bjxpbml0PgALTFRyYW5zZm9ybTsAEUxqYXZhL2xhbmcvRXJyb3I7ABJMamF2YS9sYW5nL09iamVj" + + "dDsAEkxqYXZhL2xhbmcvU3RyaW5nOwAVU2hvdWxkIG5vdCBiZSBjYWxsZWQhAA5UcmFuc2Zvcm0u" + + "amF2YQABVgACVkwAEmVtaXR0ZXI6IGphY2stNC4yMgAFZmllbGQABXNheUhpAAEABw4ABAEABw4A" + + "AAEBAQACAICABJQCAQGsAgAAAA0AAAAAAAAAAQAAAAAAAAABAAAADAAAAHAAAAACAAAABQAAAKAA" + + "AAADAAAAAgAAALQAAAAEAAAAAQAAAMwAAAAFAAAABAAAANQAAAAGAAAAAQAAAPQAAAABIAAAAgAA" + + "ABQBAAABEAAAAQAAAFABAAACIAAADAAAAFYBAAADIAAAAgAAAPYBAAAAIAAAAQAAAAECAAAAEAAA" + + "AQAAABQCAAA="); + + public static void doTest(Transform t) { + t.sayHi("NewField"); + try { + Main.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); + } catch (Exception e) { + System.out.println( + "Transformation error : " + e.getClass().getName() + "(" + e.getMessage() + ")"); + } + t.sayHi("NewField"); + } +} diff --git a/test/921-hello-failure/src/NewMethod.java b/test/921-hello-failure/src/NewMethod.java new file mode 100644 index 0000000000..5eac670c68 --- /dev/null +++ b/test/921-hello-failure/src/NewMethod.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2017 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; + +class NewMethod { + // The following is a base64 encoding of the following class. + // class Transform { + // public void extraMethod() {} + // public void sayHi(String name) { + // throw new Error("Should not be called!"); + // } + // } + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAFgoABgAQBwARCAASCgACABMHABQHABUBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAP" + + "TGluZU51bWJlclRhYmxlAQALZXh0cmFNZXRob2QBAAVzYXlIaQEAFShMamF2YS9sYW5nL1N0cmlu" + + "ZzspVgEAClNvdXJjZUZpbGUBAA5UcmFuc2Zvcm0uamF2YQwABwAIAQAPamF2YS9sYW5nL0Vycm9y" + + "AQAVU2hvdWxkIG5vdCBiZSBjYWxsZWQhDAAHAA0BAAlUcmFuc2Zvcm0BABBqYXZhL2xhbmcvT2Jq" + + "ZWN0ACAABQAGAAAAAAADAAAABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAA" + + "AQABAAsACAABAAkAAAAZAAAAAQAAAAGxAAAAAQAKAAAABgABAAAAAgABAAwADQABAAkAAAAiAAMA" + + "AgAAAAq7AAJZEgO3AAS/AAAAAQAKAAAABgABAAAABAABAA4AAAACAA8="); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQBeV7dLAwN1GBTa/yRlkuiIQatNHghVdrnIAgAAcAAAAHhWNBIAAAAAAAAAADQCAAAM" + + "AAAAcAAAAAUAAACgAAAAAgAAALQAAAAAAAAAAAAAAAUAAADMAAAAAQAAAPQAAAC0AQAAFAEAAGoB" + + "AAByAQAAfwEAAJIBAACmAQAAugEAANEBAADhAQAA5AEAAOgBAAD8AQAACQIAAAEAAAACAAAAAwAA" + + "AAQAAAAHAAAABwAAAAQAAAAAAAAACAAAAAQAAABkAQAAAAAAAAAAAAAAAAAACgAAAAAAAQALAAAA" + + "AQABAAAAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAGAAAAAAAAACACAAAAAAAAAQABAAEAAAAQ" + + "AgAABAAAAHAQBAAAAA4AAQABAAAAAAAVAgAAAQAAAA4AAAAEAAIAAgAAABoCAAAJAAAAIgABABsB" + + "BQAAAHAgAwAQACcAAAABAAAAAwAGPGluaXQ+AAtMVHJhbnNmb3JtOwARTGphdmEvbGFuZy9FcnJv" + + "cjsAEkxqYXZhL2xhbmcvT2JqZWN0OwASTGphdmEvbGFuZy9TdHJpbmc7ABVTaG91bGQgbm90IGJl" + + "IGNhbGxlZCEADlRyYW5zZm9ybS5qYXZhAAFWAAJWTAASZW1pdHRlcjogamFjay00LjIyAAtleHRy" + + "YU1ldGhvZAAFc2F5SGkAAQAHDgACAAcOAAQBAAcOAAAAAQIAgIAElAIBAawCAQHAAgAADAAAAAAA" + + "AAABAAAAAAAAAAEAAAAMAAAAcAAAAAIAAAAFAAAAoAAAAAMAAAACAAAAtAAAAAUAAAAFAAAAzAAA" + + "AAYAAAABAAAA9AAAAAEgAAADAAAAFAEAAAEQAAABAAAAZAEAAAIgAAAMAAAAagEAAAMgAAADAAAA" + + "EAIAAAAgAAABAAAAIAIAAAAQAAABAAAANAIAAA=="); + + public static void doTest(Transform t) { + t.sayHi("NewMethod"); + try { + Main.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); + } catch (Exception e) { + System.out.println( + "Transformation error : " + e.getClass().getName() + "(" + e.getMessage() + ")"); + } + t.sayHi("NewMethod"); + } +} diff --git a/test/921-hello-failure/src/Transform3.java b/test/921-hello-failure/src/Transform3.java new file mode 100644 index 0000000000..d2cb064956 --- /dev/null +++ b/test/921-hello-failure/src/Transform3.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2017 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. + */ + +class Transform3 { + public void extraMethod(String name) { + System.out.println("extraMethod - " + name); + } + public void sayHi(String name) { + System.out.println("hello2 - " + name); + } +} diff --git a/test/921-hello-failure/src/Transform4.java b/test/921-hello-failure/src/Transform4.java new file mode 100644 index 0000000000..fd763386ba --- /dev/null +++ b/test/921-hello-failure/src/Transform4.java @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2017 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. + */ + +class Transform4 { + private String greeting; + public Transform4(String hi) { + greeting = hi; + } + public void sayHi(String name) { + System.out.println("hello " + greeting + " - " + name); + } +} diff --git a/test/922-properties/run b/test/922-properties/run index 4379349cb2..c6e62ae6cd 100755 --- a/test/922-properties/run +++ b/test/922-properties/run @@ -14,6 +14,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -./default-run "$@" --experimental agents \ - --experimental runtime-plugins \ - --jvmti +./default-run "$@" --jvmti diff --git a/test/923-monitors/run b/test/923-monitors/run index 4379349cb2..c6e62ae6cd 100755 --- a/test/923-monitors/run +++ b/test/923-monitors/run @@ -14,6 +14,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -./default-run "$@" --experimental agents \ - --experimental runtime-plugins \ - --jvmti +./default-run "$@" --jvmti diff --git a/test/924-threads/run b/test/924-threads/run index 4379349cb2..c6e62ae6cd 100755 --- a/test/924-threads/run +++ b/test/924-threads/run @@ -14,6 +14,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -./default-run "$@" --experimental agents \ - --experimental runtime-plugins \ - --jvmti +./default-run "$@" --jvmti diff --git a/test/924-threads/src/Main.java b/test/924-threads/src/Main.java index 29c4aa330c..f18d70e8e1 100644 --- a/test/924-threads/src/Main.java +++ b/test/924-threads/src/Main.java @@ -20,6 +20,7 @@ import java.util.Collections; import java.util.Comparator; import java.util.concurrent.CountDownLatch; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; @@ -162,8 +163,20 @@ public class Main { private static void doAllThreadsTests() { Thread[] threads = getAllThreads(); - Arrays.sort(threads, THREAD_COMP); - System.out.println(Arrays.toString(threads)); + List<Thread> threadList = new ArrayList<>(Arrays.asList(threads)); + + // Filter out JIT thread. It may or may not be there depending on configuration. + Iterator<Thread> it = threadList.iterator(); + while (it.hasNext()) { + Thread t = it.next(); + if (t.getName().startsWith("Jit thread pool worker")) { + it.remove(); + break; + } + } + + Collections.sort(threadList, THREAD_COMP); + System.out.println(threadList); } private static void doTLSTests() throws Exception { diff --git a/test/925-threadgroups/run b/test/925-threadgroups/run index 4379349cb2..c6e62ae6cd 100755 --- a/test/925-threadgroups/run +++ b/test/925-threadgroups/run @@ -14,6 +14,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -./default-run "$@" --experimental agents \ - --experimental runtime-plugins \ - --jvmti +./default-run "$@" --jvmti diff --git a/test/925-threadgroups/src/Main.java b/test/925-threadgroups/src/Main.java index 3d7a4ca740..bf7441f9bf 100644 --- a/test/925-threadgroups/src/Main.java +++ b/test/925-threadgroups/src/Main.java @@ -14,8 +14,12 @@ * limitations under the License. */ +import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; public class Main { public static void main(String[] args) throws Exception { @@ -64,10 +68,23 @@ public class Main { Thread[] threads = (Thread[])data[0]; ThreadGroup[] groups = (ThreadGroup[])data[1]; - Arrays.sort(threads, THREAD_COMP); + List<Thread> threadList = new ArrayList<>(Arrays.asList(threads)); + + // Filter out JIT thread. It may or may not be there depending on configuration. + Iterator<Thread> it = threadList.iterator(); + while (it.hasNext()) { + Thread t = it.next(); + if (t.getName().startsWith("Jit thread pool worker")) { + it.remove(); + break; + } + } + + Collections.sort(threadList, THREAD_COMP); + Arrays.sort(groups, THREADGROUP_COMP); System.out.println(tg.getName() + ":"); - System.out.println(" " + Arrays.toString(threads)); + System.out.println(" " + threadList); System.out.println(" " + Arrays.toString(groups)); if (tg.getParent() != null) { diff --git a/test/926-multi-obsolescence/run b/test/926-multi-obsolescence/run index 4379349cb2..c6e62ae6cd 100755 --- a/test/926-multi-obsolescence/run +++ b/test/926-multi-obsolescence/run @@ -14,6 +14,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -./default-run "$@" --experimental agents \ - --experimental runtime-plugins \ - --jvmti +./default-run "$@" --jvmti diff --git a/test/927-timers/run b/test/927-timers/run index 4379349cb2..c6e62ae6cd 100755 --- a/test/927-timers/run +++ b/test/927-timers/run @@ -14,6 +14,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -./default-run "$@" --experimental agents \ - --experimental runtime-plugins \ - --jvmti +./default-run "$@" --jvmti diff --git a/test/928-jni-table/run b/test/928-jni-table/run index 4379349cb2..c6e62ae6cd 100755 --- a/test/928-jni-table/run +++ b/test/928-jni-table/run @@ -14,6 +14,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -./default-run "$@" --experimental agents \ - --experimental runtime-plugins \ - --jvmti +./default-run "$@" --jvmti diff --git a/test/929-search/run b/test/929-search/run index 0a8d0672f6..67923a7984 100755 --- a/test/929-search/run +++ b/test/929-search/run @@ -17,7 +17,5 @@ # This test checks whether dex files can be injected into parent classloaders. App images preload # classes, which will make the injection moot. Turn off app images to avoid the issue. -./default-run "$@" --experimental agents \ - --experimental runtime-plugins \ - --jvmti \ +./default-run "$@" --jvmti \ --no-app-image diff --git a/test/930-hello-retransform/run b/test/930-hello-retransform/run index 4379349cb2..c6e62ae6cd 100755 --- a/test/930-hello-retransform/run +++ b/test/930-hello-retransform/run @@ -14,6 +14,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -./default-run "$@" --experimental agents \ - --experimental runtime-plugins \ - --jvmti +./default-run "$@" --jvmti diff --git a/test/931-agent-thread/run b/test/931-agent-thread/run index 0a8d0672f6..67923a7984 100755 --- a/test/931-agent-thread/run +++ b/test/931-agent-thread/run @@ -17,7 +17,5 @@ # This test checks whether dex files can be injected into parent classloaders. App images preload # classes, which will make the injection moot. Turn off app images to avoid the issue. -./default-run "$@" --experimental agents \ - --experimental runtime-plugins \ - --jvmti \ +./default-run "$@" --jvmti \ --no-app-image diff --git a/test/932-transform-saves/run b/test/932-transform-saves/run index 4379349cb2..c6e62ae6cd 100755 --- a/test/932-transform-saves/run +++ b/test/932-transform-saves/run @@ -14,6 +14,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -./default-run "$@" --experimental agents \ - --experimental runtime-plugins \ - --jvmti +./default-run "$@" --jvmti diff --git a/test/933-misc-events/run b/test/933-misc-events/run index 0a8d0672f6..67923a7984 100755 --- a/test/933-misc-events/run +++ b/test/933-misc-events/run @@ -17,7 +17,5 @@ # This test checks whether dex files can be injected into parent classloaders. App images preload # classes, which will make the injection moot. Turn off app images to avoid the issue. -./default-run "$@" --experimental agents \ - --experimental runtime-plugins \ - --jvmti \ +./default-run "$@" --jvmti \ --no-app-image diff --git a/test/934-load-transform/build b/test/934-load-transform/build new file mode 100755 index 0000000000..898e2e54a2 --- /dev/null +++ b/test/934-load-transform/build @@ -0,0 +1,17 @@ +#!/bin/bash +# +# Copyright 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. + +./default-build "$@" --experimental agents diff --git a/test/934-load-transform/expected.txt b/test/934-load-transform/expected.txt new file mode 100644 index 0000000000..2b60207f03 --- /dev/null +++ b/test/934-load-transform/expected.txt @@ -0,0 +1 @@ +Goodbye diff --git a/test/934-load-transform/info.txt b/test/934-load-transform/info.txt new file mode 100644 index 0000000000..875a5f6ec1 --- /dev/null +++ b/test/934-load-transform/info.txt @@ -0,0 +1 @@ +Tests basic functions in the jvmti plugin. diff --git a/test/934-load-transform/run b/test/934-load-transform/run new file mode 100755 index 0000000000..adb1a1c507 --- /dev/null +++ b/test/934-load-transform/run @@ -0,0 +1,17 @@ +#!/bin/bash +# +# Copyright 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. + +./default-run "$@" --jvmti --no-app-image diff --git a/test/934-load-transform/src-ex/TestMain.java b/test/934-load-transform/src-ex/TestMain.java new file mode 100644 index 0000000000..33be9cd09d --- /dev/null +++ b/test/934-load-transform/src-ex/TestMain.java @@ -0,0 +1,21 @@ +/* + * 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. + */ + +public class TestMain { + public static void runTest() { + new Transform().sayHi(); + } +} diff --git a/test/934-load-transform/src-ex/Transform.java b/test/934-load-transform/src-ex/Transform.java new file mode 100644 index 0000000000..f624c3ac99 --- /dev/null +++ b/test/934-load-transform/src-ex/Transform.java @@ -0,0 +1,21 @@ +/* + * 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. + */ + +class Transform { + public void sayHi() { + throw new Error("Should not be called!"); + } +} diff --git a/test/934-load-transform/src/Main.java b/test/934-load-transform/src/Main.java new file mode 100644 index 0000000000..de312b03da --- /dev/null +++ b/test/934-load-transform/src/Main.java @@ -0,0 +1,95 @@ +/* + * 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.lang.reflect.*; +import java.util.Base64; + +class Main { + public static String TEST_NAME = "934-load-transform"; + + /** + * base64 encoded class/dex file for + * class Transform { + * public void sayHi() { + * System.out.println("Goodbye"); + * } + * } + */ + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAHAoABgAOCQAPABAIABEKABIAEwcAFAcAFQEABjxpbml0PgEAAygpVgEABENvZGUB" + + "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAA5UcmFuc2Zvcm0uamF2YQwA" + + "BwAIBwAWDAAXABgBAAdHb29kYnllBwAZDAAaABsBAAlUcmFuc2Zvcm0BABBqYXZhL2xhbmcvT2Jq" + + "ZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2ph" + + "dmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACAABQAG" + + "AAAAAAACAAAABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAAEQABAAsACAAB" + + "AAkAAAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAATAAgAFAABAAwAAAACAA0="); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQCLXSBQ5FiS3f16krSYZFF8xYZtFVp0GRXMAgAAcAAAAHhWNBIAAAAAAAAAACwCAAAO" + + "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACsAQAAIAEAAGIB" + + "AABqAQAAcwEAAIABAACXAQAAqwEAAL8BAADTAQAA4wEAAOYBAADqAQAA/gEAAAMCAAAMAgAAAgAA" + + "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAABAABAAsAAAAAAAAA" + + "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAHAAAAAAAAAB4CAAAA" + + "AAAAAQABAAEAAAATAgAABAAAAHAQAwAAAA4AAwABAAIAAAAYAgAACQAAAGIAAAAbAQEAAABuIAIA" + + "EAAOAAAAAQAAAAMABjxpbml0PgAHR29vZGJ5ZQALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50" + + "U3RyZWFtOwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xh" + + "bmcvU3lzdGVtOwAOVHJhbnNmb3JtLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTMuMzYAA291" + + "dAAHcHJpbnRsbgAFc2F5SGkAEQAHDgATAAcOhQAAAAEBAICABKACAQG4Ag0AAAAAAAAAAQAAAAAA" + + "AAABAAAADgAAAHAAAAACAAAABgAAAKgAAAADAAAAAgAAAMAAAAAEAAAAAQAAANgAAAAFAAAABAAA" + + "AOAAAAAGAAAAAQAAAAABAAABIAAAAgAAACABAAABEAAAAQAAAFwBAAACIAAADgAAAGIBAAADIAAA" + + "AgAAABMCAAAAIAAAAQAAAB4CAAAAEAAAAQAAACwCAAA="); + + public static ClassLoader getClassLoaderFor(String location) throws Exception { + try { + Class<?> class_loader_class = Class.forName("dalvik.system.PathClassLoader"); + Constructor<?> ctor = class_loader_class.getConstructor(String.class, ClassLoader.class); + /* on Dalvik, this is a DexFile; otherwise, it's null */ + return (ClassLoader)ctor.newInstance(location + "/" + TEST_NAME + "-ex.jar", + Main.class.getClassLoader()); + } catch (ClassNotFoundException e) { + // Running on RI. Use URLClassLoader. + return new java.net.URLClassLoader( + new java.net.URL[] { new java.net.URL("file://" + location + "/classes-ex/") }); + } + } + + public static void main(String[] args) { + // Don't pop transformations. Make sure that even if 2 threads race to define the class both + // will get the same result. + setPopRetransformations(false); + addCommonTransformationResult("Transform", CLASS_BYTES, DEX_BYTES); + enableCommonRetransformation(true); + try { + /* this is the "alternate" DEX/Jar file */ + ClassLoader new_loader = getClassLoaderFor(System.getenv("DEX_LOCATION")); + Class<?> klass = (Class<?>)new_loader.loadClass("TestMain"); + if (klass == null) { + throw new AssertionError("loadClass failed"); + } + Method run_test = klass.getMethod("runTest"); + run_test.invoke(null); + } catch (Exception e) { + System.out.println(e.toString()); + e.printStackTrace(); + } + } + + private static native void setPopRetransformations(boolean should_pop); + // Transforms the class + private static native void enableCommonRetransformation(boolean enable); + private static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/935-non-retransformable/build b/test/935-non-retransformable/build new file mode 100755 index 0000000000..898e2e54a2 --- /dev/null +++ b/test/935-non-retransformable/build @@ -0,0 +1,17 @@ +#!/bin/bash +# +# Copyright 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. + +./default-build "$@" --experimental agents diff --git a/test/935-non-retransformable/expected.txt b/test/935-non-retransformable/expected.txt new file mode 100644 index 0000000000..ccd50a66a0 --- /dev/null +++ b/test/935-non-retransformable/expected.txt @@ -0,0 +1,6 @@ +Hello +Hello +Goodbye +Hello +Hello +Goodbye diff --git a/test/935-non-retransformable/info.txt b/test/935-non-retransformable/info.txt new file mode 100644 index 0000000000..875a5f6ec1 --- /dev/null +++ b/test/935-non-retransformable/info.txt @@ -0,0 +1 @@ +Tests basic functions in the jvmti plugin. diff --git a/test/935-non-retransformable/run b/test/935-non-retransformable/run new file mode 100755 index 0000000000..adb1a1c507 --- /dev/null +++ b/test/935-non-retransformable/run @@ -0,0 +1,17 @@ +#!/bin/bash +# +# Copyright 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. + +./default-run "$@" --jvmti --no-app-image diff --git a/test/935-non-retransformable/src-ex/TestMain.java b/test/935-non-retransformable/src-ex/TestMain.java new file mode 100644 index 0000000000..d412fba37a --- /dev/null +++ b/test/935-non-retransformable/src-ex/TestMain.java @@ -0,0 +1,30 @@ +/* + * 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.lang.reflect.Method; + +public class TestMain { + public static void runTest() throws Exception { + Transform t = new Transform(); + // Call functions with reflection. Since the sayGoodbye function does not exist in the + // LTransform; when we compile this for the first time we need to use reflection. + Method hi = Transform.class.getMethod("sayHi"); + Method bye = Transform.class.getMethod("sayGoodbye"); + hi.invoke(t); + t.sayHi(); + bye.invoke(t); + } +} diff --git a/test/935-non-retransformable/src-ex/Transform.java b/test/935-non-retransformable/src-ex/Transform.java new file mode 100644 index 0000000000..f624c3ac99 --- /dev/null +++ b/test/935-non-retransformable/src-ex/Transform.java @@ -0,0 +1,21 @@ +/* + * 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. + */ + +class Transform { + public void sayHi() { + throw new Error("Should not be called!"); + } +} diff --git a/test/935-non-retransformable/src/Main.java b/test/935-non-retransformable/src/Main.java new file mode 100644 index 0000000000..82ba197b7e --- /dev/null +++ b/test/935-non-retransformable/src/Main.java @@ -0,0 +1,110 @@ +/* + * 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.lang.reflect.*; +import java.util.Base64; + +class Main { + public static String TEST_NAME = "935-non-retransformable"; + + /** + * base64 encoded class/dex file for + * class Transform { + * public void sayHi() { + * System.out.println("Hello"); + * } + * public void sayGoodbye() { + * System.out.println("Goodbye"); + * } + * } + */ + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAHwoABwAQCQARABIIABMKABQAFQgAFgcAFwcAGAEABjxpbml0PgEAAygpVgEABENv" + + "ZGUBAA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEACnNheUdvb2RieWUBAApTb3VyY2VGaWxlAQAO" + + "VHJhbnNmb3JtLmphdmEMAAgACQcAGQwAGgAbAQAFSGVsbG8HABwMAB0AHgEAB0dvb2RieWUBAAlU" + + "cmFuc2Zvcm0BABBqYXZhL2xhbmcvT2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxq" + + "YXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExq" + + "YXZhL2xhbmcvU3RyaW5nOylWACAABgAHAAAAAAADAAAACAAJAAEACgAAAB0AAQABAAAABSq3AAGx" + + "AAAAAQALAAAABgABAAAAAQABAAwACQABAAoAAAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAsAAAAK" + + "AAIAAAADAAgABAABAA0ACQABAAoAAAAlAAIAAQAAAAmyAAISBbYABLEAAAABAAsAAAAKAAIAAAAG" + + "AAgABwABAA4AAAACAA8="); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQDpaN+7jX/ZLl9Jr0HAEV7nqL1YDuakKakgAwAAcAAAAHhWNBIAAAAAAAAAAIACAAAQ" + + "AAAAcAAAAAYAAACwAAAAAgAAAMgAAAABAAAA4AAAAAUAAADoAAAAAQAAABABAADwAQAAMAEAAJYB" + + "AACeAQAApwEAAK4BAAC7AQAA0gEAAOYBAAD6AQAADgIAAB4CAAAhAgAAJQIAADkCAAA+AgAARwIA" + + "AFMCAAADAAAABAAAAAUAAAAGAAAABwAAAAkAAAAJAAAABQAAAAAAAAAKAAAABQAAAJABAAAEAAEA" + + "DAAAAAAAAAAAAAAAAAAAAA4AAAAAAAAADwAAAAEAAQANAAAAAgAAAAAAAAAAAAAAAAAAAAIAAAAA" + + "AAAACAAAAAAAAABrAgAAAAAAAAEAAQABAAAAWgIAAAQAAABwEAQAAAAOAAMAAQACAAAAXwIAAAkA" + + "AABiAAAAGwEBAAAAbiADABAADgAAAAMAAQACAAAAZQIAAAkAAABiAAAAGwECAAAAbiADABAADgAA" + + "AAEAAAADAAY8aW5pdD4AB0dvb2RieWUABUhlbGxvAAtMVHJhbnNmb3JtOwAVTGphdmEvaW8vUHJp" + + "bnRTdHJlYW07ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEv" + + "bGFuZy9TeXN0ZW07AA5UcmFuc2Zvcm0uamF2YQABVgACVkwAEmVtaXR0ZXI6IGphY2stNC4yMgAD" + + "b3V0AAdwcmludGxuAApzYXlHb29kYnllAAVzYXlIaQABAAcOAAYABw6HAAMABw6HAAAAAQIAgIAE" + + "sAIBAcgCAQHsAgAAAA0AAAAAAAAAAQAAAAAAAAABAAAAEAAAAHAAAAACAAAABgAAALAAAAADAAAA" + + "AgAAAMgAAAAEAAAAAQAAAOAAAAAFAAAABQAAAOgAAAAGAAAAAQAAABABAAABIAAAAwAAADABAAAB" + + "EAAAAQAAAJABAAACIAAAEAAAAJYBAAADIAAAAwAAAFoCAAAAIAAAAQAAAGsCAAAAEAAAAQAAAIAC" + + "AAA="); + + + public static ClassLoader getClassLoaderFor(String location) throws Exception { + try { + Class<?> class_loader_class = Class.forName("dalvik.system.PathClassLoader"); + Constructor<?> ctor = class_loader_class.getConstructor(String.class, ClassLoader.class); + /* on Dalvik, this is a DexFile; otherwise, it's null */ + return (ClassLoader)ctor.newInstance(location + "/" + TEST_NAME + "-ex.jar", + Main.class.getClassLoader()); + } catch (ClassNotFoundException e) { + // Running on RI. Use URLClassLoader. + return new java.net.URLClassLoader( + new java.net.URL[] { new java.net.URL("file://" + location + "/classes-ex/") }); + } + } + + public static void main(String[] args) { + setPopRetransformations(false); + addCommonTransformationResult("Transform", CLASS_BYTES, DEX_BYTES); + enableCommonRetransformation(true); + try { + /* this is the "alternate" DEX/Jar file */ + ClassLoader new_loader = getClassLoaderFor(System.getenv("DEX_LOCATION")); + Class<?> klass = (Class<?>)new_loader.loadClass("TestMain"); + if (klass == null) { + throw new AssertionError("loadClass failed"); + } + Method run_test = klass.getMethod("runTest"); + run_test.invoke(null); + + // Remove the original transformation. It has been used by now. + popTransformationFor("Transform"); + // Make sure we don't get called for transformation again. + addCommonTransformationResult("Transform", new byte[0], new byte[0]); + doCommonClassRetransformation(new_loader.loadClass("Transform")); + run_test.invoke(null); + } catch (Exception e) { + System.out.println(e.toString()); + e.printStackTrace(); + } + } + + // Transforms the class + private static native void doCommonClassRetransformation(Class<?>... classes); + private static native void enableCommonRetransformation(boolean enable); + private static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); + private static native void setPopRetransformations(boolean should_pop); + private static native void popTransformationFor(String target_name); +} diff --git a/test/936-search-onload/build b/test/936-search-onload/build new file mode 100755 index 0000000000..898e2e54a2 --- /dev/null +++ b/test/936-search-onload/build @@ -0,0 +1,17 @@ +#!/bin/bash +# +# Copyright 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. + +./default-build "$@" --experimental agents diff --git a/test/936-search-onload/expected.txt b/test/936-search-onload/expected.txt new file mode 100644 index 0000000000..2eec8e1aac --- /dev/null +++ b/test/936-search-onload/expected.txt @@ -0,0 +1,3 @@ +B was loaded with boot classloader +A was loaded with system classloader +Done diff --git a/test/936-search-onload/info.txt b/test/936-search-onload/info.txt new file mode 100644 index 0000000000..875a5f6ec1 --- /dev/null +++ b/test/936-search-onload/info.txt @@ -0,0 +1 @@ +Tests basic functions in the jvmti plugin. diff --git a/test/936-search-onload/run b/test/936-search-onload/run new file mode 100755 index 0000000000..67923a7984 --- /dev/null +++ b/test/936-search-onload/run @@ -0,0 +1,21 @@ +#!/bin/bash +# +# Copyright 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. + +# This test checks whether dex files can be injected into parent classloaders. App images preload +# classes, which will make the injection moot. Turn off app images to avoid the issue. + +./default-run "$@" --jvmti \ + --no-app-image diff --git a/test/936-search-onload/search_onload.cc b/test/936-search-onload/search_onload.cc new file mode 100644 index 0000000000..2286a467d3 --- /dev/null +++ b/test/936-search-onload/search_onload.cc @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2017 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. + */ + +#include "search_onload.h" + +#include <inttypes.h> + +#include "android-base/stringprintf.h" +#include "base/logging.h" +#include "base/macros.h" +#include "jni.h" +#include "openjdkjvmti/jvmti.h" +#include "ScopedUtfChars.h" + +#include "ti-agent/common_helper.h" +#include "ti-agent/common_load.h" + +namespace art { +namespace Test936SearchOnload { + +jint OnLoad(JavaVM* vm, + char* options ATTRIBUTE_UNUSED, + void* reserved ATTRIBUTE_UNUSED) { + if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0)) { + printf("Unable to get jvmti env!\n"); + return 1; + } + SetAllCapabilities(jvmti_env); + + char* dex_loc = getenv("DEX_LOCATION"); + std::string dex1 = android::base::StringPrintf("%s/936-search-onload.jar", dex_loc); + std::string dex2 = android::base::StringPrintf("%s/936-search-onload-ex.jar", dex_loc); + + jvmtiError result = jvmti_env->AddToBootstrapClassLoaderSearch(dex1.c_str()); + if (result != JVMTI_ERROR_NONE) { + printf("Could not add to bootstrap classloader.\n"); + return 1; + } + + result = jvmti_env->AddToSystemClassLoaderSearch(dex2.c_str()); + if (result != JVMTI_ERROR_NONE) { + printf("Could not add to system classloader.\n"); + return 1; + } + + return JNI_OK; +} + +} // namespace Test936SearchOnload +} // namespace art diff --git a/test/936-search-onload/search_onload.h b/test/936-search-onload/search_onload.h new file mode 100644 index 0000000000..e55689252d --- /dev/null +++ b/test/936-search-onload/search_onload.h @@ -0,0 +1,30 @@ +/* + * 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. + */ + +#ifndef ART_TEST_936_SEARCH_ONLOAD_SEARCH_ONLOAD_H_ +#define ART_TEST_936_SEARCH_ONLOAD_SEARCH_ONLOAD_H_ + +#include <jni.h> + +namespace art { +namespace Test936SearchOnload { + +jint OnLoad(JavaVM* vm, char* options, void* reserved); + +} // namespace Test936SearchOnload +} // namespace art + +#endif // ART_TEST_936_SEARCH_ONLOAD_SEARCH_ONLOAD_H_ diff --git a/test/936-search-onload/src-ex/A.java b/test/936-search-onload/src-ex/A.java new file mode 100644 index 0000000000..64acb2fcfe --- /dev/null +++ b/test/936-search-onload/src-ex/A.java @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2017 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. + */ + +public class A { +}
\ No newline at end of file diff --git a/test/936-search-onload/src/B.java b/test/936-search-onload/src/B.java new file mode 100644 index 0000000000..f1458c3bca --- /dev/null +++ b/test/936-search-onload/src/B.java @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2017 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. + */ + +public class B { +}
\ No newline at end of file diff --git a/test/936-search-onload/src/Main.java b/test/936-search-onload/src/Main.java new file mode 100644 index 0000000000..2e7a87193b --- /dev/null +++ b/test/936-search-onload/src/Main.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2017 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.Arrays; + +public class Main { + public static void main(String[] args) throws Exception { + doTest(); + } + + private static void doTest() throws Exception { + doTest(true, "B"); + doTest(false, "A"); + System.out.println("Done"); + } + + private static void doTest(boolean boot, String className) throws Exception { + ClassLoader expectedClassLoader; + if (boot) { + expectedClassLoader = Object.class.getClassLoader(); + } else { + expectedClassLoader = ClassLoader.getSystemClassLoader(); + } + + Class<?> c = Class.forName(className, false, ClassLoader.getSystemClassLoader()); + if (c.getClassLoader() != expectedClassLoader) { + throw new RuntimeException(className + "(" + boot + "): " + + c.getClassLoader() + " vs " + expectedClassLoader); + } else { + System.out.println(className + " was loaded with " + (boot ? "boot" : "system") + + " classloader"); + } + } +} diff --git a/test/937-hello-retransform-package/build b/test/937-hello-retransform-package/build new file mode 100755 index 0000000000..898e2e54a2 --- /dev/null +++ b/test/937-hello-retransform-package/build @@ -0,0 +1,17 @@ +#!/bin/bash +# +# Copyright 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. + +./default-build "$@" --experimental agents diff --git a/test/937-hello-retransform-package/expected.txt b/test/937-hello-retransform-package/expected.txt new file mode 100644 index 0000000000..4774b81b49 --- /dev/null +++ b/test/937-hello-retransform-package/expected.txt @@ -0,0 +1,2 @@ +hello +Goodbye diff --git a/test/937-hello-retransform-package/info.txt b/test/937-hello-retransform-package/info.txt new file mode 100644 index 0000000000..875a5f6ec1 --- /dev/null +++ b/test/937-hello-retransform-package/info.txt @@ -0,0 +1 @@ +Tests basic functions in the jvmti plugin. diff --git a/test/937-hello-retransform-package/run b/test/937-hello-retransform-package/run new file mode 100755 index 0000000000..c6e62ae6cd --- /dev/null +++ b/test/937-hello-retransform-package/run @@ -0,0 +1,17 @@ +#!/bin/bash +# +# Copyright 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. + +./default-run "$@" --jvmti diff --git a/test/937-hello-retransform-package/src/Main.java b/test/937-hello-retransform-package/src/Main.java new file mode 100644 index 0000000000..4b9271b4f4 --- /dev/null +++ b/test/937-hello-retransform-package/src/Main.java @@ -0,0 +1,73 @@ +/* + * 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 testing.*; +public class Main { + + /** + * base64 encoded class/dex file for + * package testing; + * class Transform { + * public void sayHi() { + * System.out.println("Goodbye"); + * } + * } + */ + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAHAoABgAOCQAPABAIABEKABIAEwcAFAcAFQEABjxpbml0PgEAAygpVgEABENvZGUB" + + "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAA5UcmFuc2Zvcm0uamF2YQwA" + + "BwAIBwAWDAAXABgBAAdHb29kYnllBwAZDAAaABsBABF0ZXN0aW5nL1RyYW5zZm9ybQEAEGphdmEv" + + "bGFuZy9PYmplY3QBABBqYXZhL2xhbmcvU3lzdGVtAQADb3V0AQAVTGphdmEvaW8vUHJpbnRTdHJl" + + "YW07AQATamF2YS9pby9QcmludFN0cmVhbQEAB3ByaW50bG4BABUoTGphdmEvbGFuZy9TdHJpbmc7" + + "KVYAIQAFAAYAAAAAAAIAAQAHAAgAAQAJAAAAHQABAAEAAAAFKrcAAbEAAAABAAoAAAAGAAEAAAAC" + + "AAEACwAIAAEACQAAACUAAgABAAAACbIAAhIDtgAEsQAAAAEACgAAAAoAAgAAAAQACAAFAAEADAAA" + + "AAIADQ=="); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQBhYIi3Gs9Nn/GN1fCzF+aFQ0AbhA1h1WHUAgAAcAAAAHhWNBIAAAAAAAAAADQCAAAO" + + "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAAC0AQAAIAEAAGIB" + + "AABqAQAAcwEAAIoBAACeAQAAsgEAAMYBAADbAQAA6wEAAO4BAADyAQAABgIAAAsCAAAUAgAAAgAA" + + "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAAAwAAAAsAAAAAAAEA" + + "DAAAAAEAAAAAAAAABAAAAAAAAAAEAAAADQAAAAQAAAABAAAAAQAAAAAAAAAHAAAAAAAAACYCAAAA" + + "AAAAAQABAAEAAAAbAgAABAAAAHAQAQAAAA4AAwABAAIAAAAgAgAACQAAAGIAAAAbAQEAAABuIAAA" + + "EAAOAAAAAQAAAAIABjxpbml0PgAHR29vZGJ5ZQAVTGphdmEvaW8vUHJpbnRTdHJlYW07ABJMamF2" + + "YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEvbGFuZy9TeXN0ZW07ABNM" + + "dGVzdGluZy9UcmFuc2Zvcm07AA5UcmFuc2Zvcm0uamF2YQABVgACVkwAEmVtaXR0ZXI6IGphY2st" + + "NC4yMgADb3V0AAdwcmludGxuAAVzYXlIaQACAAcOAAQABw6HAAAAAQECgYAEoAIDAbgCDQAAAAAA" + + "AAABAAAAAAAAAAEAAAAOAAAAcAAAAAIAAAAGAAAAqAAAAAMAAAACAAAAwAAAAAQAAAABAAAA2AAA" + + "AAUAAAAEAAAA4AAAAAYAAAABAAAAAAEAAAEgAAACAAAAIAEAAAEQAAABAAAAXAEAAAIgAAAOAAAA" + + "YgEAAAMgAAACAAAAGwIAAAAgAAABAAAAJgIAAAAQAAABAAAANAIAAA=="); + + public static void main(String[] args) { + doTest(new Transform()); + } + + public static void doTest(Transform t) { + t.sayHi(); + addCommonTransformationResult("testing/Transform", CLASS_BYTES, DEX_BYTES); + enableCommonRetransformation(true); + doCommonClassRetransformation(Transform.class); + t.sayHi(); + } + + // Transforms the class + private static native void doCommonClassRetransformation(Class<?>... target); + private static native void enableCommonRetransformation(boolean enable); + private static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/937-hello-retransform-package/src/Transform.java b/test/937-hello-retransform-package/src/Transform.java new file mode 100644 index 0000000000..db92612299 --- /dev/null +++ b/test/937-hello-retransform-package/src/Transform.java @@ -0,0 +1,22 @@ +/* + * 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. + */ + +package testing; +public class Transform { + public void sayHi() { + System.out.println("hello"); + } +} diff --git a/test/938-load-transform-bcp/build b/test/938-load-transform-bcp/build new file mode 100755 index 0000000000..898e2e54a2 --- /dev/null +++ b/test/938-load-transform-bcp/build @@ -0,0 +1,17 @@ +#!/bin/bash +# +# Copyright 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. + +./default-build "$@" --experimental agents diff --git a/test/938-load-transform-bcp/expected.txt b/test/938-load-transform-bcp/expected.txt new file mode 100644 index 0000000000..16c3f8f726 --- /dev/null +++ b/test/938-load-transform-bcp/expected.txt @@ -0,0 +1,2 @@ +ol.foo() -> 'This is foo for val=123' +ol.toString() -> 'This is toString() for val=123' diff --git a/test/938-load-transform-bcp/info.txt b/test/938-load-transform-bcp/info.txt new file mode 100644 index 0000000000..875a5f6ec1 --- /dev/null +++ b/test/938-load-transform-bcp/info.txt @@ -0,0 +1 @@ +Tests basic functions in the jvmti plugin. diff --git a/test/938-load-transform-bcp/run b/test/938-load-transform-bcp/run new file mode 100755 index 0000000000..adb1a1c507 --- /dev/null +++ b/test/938-load-transform-bcp/run @@ -0,0 +1,17 @@ +#!/bin/bash +# +# Copyright 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. + +./default-run "$@" --jvmti --no-app-image diff --git a/test/938-load-transform-bcp/src-ex/TestMain.java b/test/938-load-transform-bcp/src-ex/TestMain.java new file mode 100644 index 0000000000..3757a0f778 --- /dev/null +++ b/test/938-load-transform-bcp/src-ex/TestMain.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2017 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.lang.reflect.Method; +import java.util.OptionalLong; +public class TestMain { + public static void runTest() { + // This should be our redefined OptionalLong. + OptionalLong ol = OptionalLong.of(123); + try { + // OptionalLong is a class that is unlikely to be used by the time this test starts. + Method foo = OptionalLong.class.getMethod("foo"); + System.out.println("ol.foo() -> '" + (String)foo.invoke(ol) + "'"); + System.out.println("ol.toString() -> '" + ol.toString() + "'"); + } catch (Exception e) { + System.out.println( + "Exception occured (did something load OptionalLong before this test method!: " + + e.toString()); + e.printStackTrace(); + } + } +} diff --git a/test/938-load-transform-bcp/src/Main.java b/test/938-load-transform-bcp/src/Main.java new file mode 100644 index 0000000000..548489939e --- /dev/null +++ b/test/938-load-transform-bcp/src/Main.java @@ -0,0 +1,123 @@ +/* + * 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.lang.reflect.*; +import java.util.Base64; + +class Main { + public static String TEST_NAME = "938-load-transform-bcp"; + + /** + * base64 encoded class/dex file for + * + * // Yes this version of OptionalLong is not compatible with the real one but since it isn't used + * // for anything in the runtime initialization it should be fine. + * + * package java.util; + * public final class OptionalLong { + * private long val; + * + * private OptionalLong(long abc) { + * this.val = abc; + * } + * + * public static OptionalLong of(long abc) { + * return new OptionalLong(abc); + * } + * + * public String foo() { + * return "This is foo for val=" + val; + * } + * + * public String toString() { + * return "This is toString() for val=" + val; + * } + * } + */ + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAKQoADAAaCQADABsHABwKAAMAHQcAHgoABQAaCAAfCgAFACAKAAUAIQoABQAiCAAj" + + "BwAkAQADdmFsAQABSgEABjxpbml0PgEABChKKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQAC" + + "b2YBABsoSilMamF2YS91dGlsL09wdGlvbmFsTG9uZzsBAANmb28BABQoKUxqYXZhL2xhbmcvU3Ry" + + "aW5nOwEACHRvU3RyaW5nAQAKU291cmNlRmlsZQEAEU9wdGlvbmFsTG9uZy5qYXZhDAAPACUMAA0A" + + "DgEAFmphdmEvdXRpbC9PcHRpb25hbExvbmcMAA8AEAEAF2phdmEvbGFuZy9TdHJpbmdCdWlsZGVy" + + "AQAUVGhpcyBpcyBmb28gZm9yIHZhbD0MACYAJwwAJgAoDAAXABYBABtUaGlzIGlzIHRvU3RyaW5n" + + "KCkgZm9yIHZhbD0BABBqYXZhL2xhbmcvT2JqZWN0AQADKClWAQAGYXBwZW5kAQAtKExqYXZhL2xh" + + "bmcvU3RyaW5nOylMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7AQAcKEopTGphdmEvbGFuZy9TdHJp" + + "bmdCdWlsZGVyOwAxAAMADAAAAAEAAgANAA4AAAAEAAIADwAQAAEAEQAAACoAAwADAAAACiq3AAEq" + + "H7UAArEAAAABABIAAAAOAAMAAAAFAAQABgAJAAcACQATABQAAQARAAAAIQAEAAIAAAAJuwADWR63" + + "AASwAAAAAQASAAAABgABAAAACgABABUAFgABABEAAAAvAAMAAQAAABe7AAVZtwAGEge2AAgqtAAC" + + "tgAJtgAKsAAAAAEAEgAAAAYAAQAAAA4AAQAXABYAAQARAAAALwADAAEAAAAXuwAFWbcABhILtgAI" + + "KrQAArYACbYACrAAAAABABIAAAAGAAEAAAASAAEAGAAAAAIAGQ=="); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQAOe/TYJCvVthTToFA3tveMDhwTo7uDf0IcBAAAcAAAAHhWNBIAAAAAAAAAAHwDAAAU" + + "AAAAcAAAAAYAAADAAAAABgAAANgAAAABAAAAIAEAAAkAAAAoAQAAAQAAAHABAACMAgAAkAEAAFYC" + + "AABeAgAAYQIAAGQCAABoAgAAbAIAAIACAACUAgAArwIAAMkCAADcAgAA8gIAAA8DAAASAwAAFgMA" + + "AB4DAAAyAwAANwMAADsDAABFAwAAAQAAAAUAAAAGAAAABwAAAAgAAAAMAAAAAgAAAAIAAAAAAAAA" + + "AwAAAAMAAABIAgAABAAAAAMAAABQAgAAAwAAAAQAAABIAgAADAAAAAUAAAAAAAAADQAAAAUAAABI" + + "AgAABAAAABMAAAABAAQAAAAAAAMABAAAAAAAAwABAA4AAAADAAIADgAAAAMAAAASAAAABAAFAAAA" + + "AAAEAAAAEAAAAAQAAwARAAAABAAAABIAAAAEAAAAEQAAAAEAAAAAAAAACQAAAAAAAABiAwAAAAAA" + + "AAQAAwABAAAASgMAAAYAAABwEAAAAQBaEgAADgAEAAIAAwAAAFIDAAAGAAAAIgAEAHAwBQAgAxEA" + + "BQABAAMAAABYAwAAFwAAACIAAwBwEAEAAAAbAQoAAABuIAMAEAAMAFNCAABuMAIAIAMMAG4QBAAA" + + "AAwAEQAAAAUAAQADAAAAXQMAABcAAAAiAAMAcBABAAAAGwELAAAAbiADABAADABTQgAAbjACACAD" + + "DABuEAQAAAAMABEAAAABAAAAAAAAAAEAAAACAAY8aW5pdD4AAUoAAUwAAkxKAAJMTAASTGphdmEv" + + "bGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAGUxqYXZhL2xhbmcvU3RyaW5nQnVpbGRl" + + "cjsAGExqYXZhL3V0aWwvT3B0aW9uYWxMb25nOwART3B0aW9uYWxMb25nLmphdmEAFFRoaXMgaXMg" + + "Zm9vIGZvciB2YWw9ABtUaGlzIGlzIHRvU3RyaW5nKCkgZm9yIHZhbD0AAVYAAlZKAAZhcHBlbmQA" + + "EmVtaXR0ZXI6IGphY2stNC4yMgADZm9vAAJvZgAIdG9TdHJpbmcAA3ZhbAAFAQAHDjwtAAoBAAcO" + + "AA4ABw4AEgAHDgAAAQICAAIFgoAEkAMCCawDBgHIAwIBiAQAAA0AAAAAAAAAAQAAAAAAAAABAAAA" + + "FAAAAHAAAAACAAAABgAAAMAAAAADAAAABgAAANgAAAAEAAAAAQAAACABAAAFAAAACQAAACgBAAAG" + + "AAAAAQAAAHABAAABIAAABAAAAJABAAABEAAAAgAAAEgCAAACIAAAFAAAAFYCAAADIAAABAAAAEoD" + + "AAAAIAAAAQAAAGIDAAAAEAAAAQAAAHwDAAA="); + + public static ClassLoader getClassLoaderFor(String location) throws Exception { + try { + Class<?> class_loader_class = Class.forName("dalvik.system.PathClassLoader"); + Constructor<?> ctor = class_loader_class.getConstructor(String.class, ClassLoader.class); + return (ClassLoader)ctor.newInstance(location + "/" + TEST_NAME + "-ex.jar", + Main.class.getClassLoader()); + } catch (ClassNotFoundException e) { + // Running on RI. Use URLClassLoader. + return new java.net.URLClassLoader( + new java.net.URL[] { new java.net.URL("file://" + location + "/classes-ex/") }); + } + } + + public static void main(String[] args) { + setPopRetransformations(false); + addCommonTransformationResult("java/util/OptionalLong", CLASS_BYTES, DEX_BYTES); + enableCommonRetransformation(true); + try { + /* this is the "alternate" DEX/Jar file */ + ClassLoader new_loader = getClassLoaderFor(System.getenv("DEX_LOCATION")); + Class<?> klass = (Class<?>)new_loader.loadClass("TestMain"); + if (klass == null) { + throw new AssertionError("loadClass failed"); + } + Method run_test = klass.getMethod("runTest"); + run_test.invoke(null); + } catch (Exception e) { + System.out.println(e.toString()); + e.printStackTrace(); + } + } + + private static native void setPopRetransformations(boolean should_pop); + // Transforms the class + private static native void enableCommonRetransformation(boolean enable); + private static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/939-hello-transformation-bcp/build b/test/939-hello-transformation-bcp/build new file mode 100755 index 0000000000..898e2e54a2 --- /dev/null +++ b/test/939-hello-transformation-bcp/build @@ -0,0 +1,17 @@ +#!/bin/bash +# +# Copyright 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. + +./default-build "$@" --experimental agents diff --git a/test/939-hello-transformation-bcp/expected.txt b/test/939-hello-transformation-bcp/expected.txt new file mode 100644 index 0000000000..90fd25828d --- /dev/null +++ b/test/939-hello-transformation-bcp/expected.txt @@ -0,0 +1,3 @@ +ol.toString() -> 'OptionalLong[-559038737]' +Redefining OptionalLong! +ol.toString() -> 'Redefined OptionalLong!' diff --git a/test/939-hello-transformation-bcp/info.txt b/test/939-hello-transformation-bcp/info.txt new file mode 100644 index 0000000000..d230a382bd --- /dev/null +++ b/test/939-hello-transformation-bcp/info.txt @@ -0,0 +1,6 @@ +Tests basic functions in the jvmti plugin. + +Note this function is reliant on the definition of java.util.OptionalLong not +changing. If this classes definition changes we will need to update this class +so that the CLASS_BYTES and DEX_BYTES fields contain dex/class bytes for an +OptionalLong with all the same methods and fields. diff --git a/test/939-hello-transformation-bcp/run b/test/939-hello-transformation-bcp/run new file mode 100755 index 0000000000..c6e62ae6cd --- /dev/null +++ b/test/939-hello-transformation-bcp/run @@ -0,0 +1,17 @@ +#!/bin/bash +# +# Copyright 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. + +./default-run "$@" --jvmti diff --git a/test/939-hello-transformation-bcp/src/Main.java b/test/939-hello-transformation-bcp/src/Main.java new file mode 100644 index 0000000000..bdf7f592ef --- /dev/null +++ b/test/939-hello-transformation-bcp/src/Main.java @@ -0,0 +1,126 @@ +/* + * 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.OptionalLong; +public class Main { + + /** + * This is the base64 encoded class/dex. + * + * package java.util; + * import java.util.function.LongConsumer; + * import java.util.function.LongSupplier; + * import java.util.function.Supplier; + * public final class OptionalLong { + * // Make sure we have a <clinit> function since the real implementation of OptionalLong does. + * static { EMPTY = null; } + * private static final OptionalLong EMPTY; + * private final boolean isPresent; + * private final long value; + * private OptionalLong() { isPresent = false; value = 0; } + * private OptionalLong(long l) { this(); } + * public static OptionalLong empty() { return null; } + * public static OptionalLong of(long value) { return null; } + * public long getAsLong() { return 0; } + * public boolean isPresent() { return false; } + * public void ifPresent(LongConsumer c) { } + * public long orElse(long l) { return 0; } + * public long orElseGet(LongSupplier s) { return 0; } + * public<X extends Throwable> long orElseThrow(Supplier<X> s) throws X { return 0; } + * public boolean equals(Object o) { return false; } + * public int hashCode() { return 0; } + * public String toString() { return "Redefined OptionalLong!"; } + * } + */ + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAOAoACAAwCQAHADEJAAcAMgoABwAwCAAzCQAHADQHADUHADYBAAVFTVBUWQEAGExq" + + "YXZhL3V0aWwvT3B0aW9uYWxMb25nOwEACWlzUHJlc2VudAEAAVoBAAV2YWx1ZQEAAUoBAAY8aW5p" + + "dD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQAEKEopVgEABWVtcHR5AQAaKClMamF2" + + "YS91dGlsL09wdGlvbmFsTG9uZzsBAAJvZgEAGyhKKUxqYXZhL3V0aWwvT3B0aW9uYWxMb25nOwEA" + + "CWdldEFzTG9uZwEAAygpSgEAAygpWgEACWlmUHJlc2VudAEAJChMamF2YS91dGlsL2Z1bmN0aW9u" + + "L0xvbmdDb25zdW1lcjspVgEABm9yRWxzZQEABChKKUoBAAlvckVsc2VHZXQBACQoTGphdmEvdXRp" + + "bC9mdW5jdGlvbi9Mb25nU3VwcGxpZXI7KUoBAAtvckVsc2VUaHJvdwEAIChMamF2YS91dGlsL2Z1" + + "bmN0aW9uL1N1cHBsaWVyOylKAQAKRXhjZXB0aW9ucwcANwEACVNpZ25hdHVyZQEAQjxYOkxqYXZh" + + "L2xhbmcvVGhyb3dhYmxlOz4oTGphdmEvdXRpbC9mdW5jdGlvbi9TdXBwbGllcjxUWDs+OylKXlRY" + + "OwEABmVxdWFscwEAFShMamF2YS9sYW5nL09iamVjdDspWgEACGhhc2hDb2RlAQADKClJAQAIdG9T" + + "dHJpbmcBABQoKUxqYXZhL2xhbmcvU3RyaW5nOwEACDxjbGluaXQ+AQAKU291cmNlRmlsZQEAEU9w" + + "dGlvbmFsTG9uZy5qYXZhDAAPABAMAAsADAwADQAOAQAXUmVkZWZpbmVkIE9wdGlvbmFsTG9uZyEM" + + "AAkACgEAFmphdmEvdXRpbC9PcHRpb25hbExvbmcBABBqYXZhL2xhbmcvT2JqZWN0AQATamF2YS9s" + + "YW5nL1Rocm93YWJsZQAxAAcACAAAAAMAGgAJAAoAAAASAAsADAAAABIADQAOAAAADgACAA8AEAAB" + + "ABEAAAAnAAMAAQAAAA8qtwABKgO1AAIqCbUAA7EAAAABABIAAAAGAAEAAAALAAIADwATAAEAEQAA" + + "AB0AAQADAAAABSq3AASxAAAAAQASAAAABgABAAAADAAJABQAFQABABEAAAAaAAEAAAAAAAIBsAAA" + + "AAEAEgAAAAYAAQAAAA0ACQAWABcAAQARAAAAGgABAAIAAAACAbAAAAABABIAAAAGAAEAAAAOAAEA" + + "GAAZAAEAEQAAABoAAgABAAAAAgmtAAAAAQASAAAABgABAAAADwABAAsAGgABABEAAAAaAAEAAQAA" + + "AAIDrAAAAAEAEgAAAAYAAQAAABAAAQAbABwAAQARAAAAGQAAAAIAAAABsQAAAAEAEgAAAAYAAQAA" + + "ABEAAQAdAB4AAQARAAAAGgACAAMAAAACCa0AAAABABIAAAAGAAEAAAASAAEAHwAgAAEAEQAAABoA" + + "AgACAAAAAgmtAAAAAQASAAAABgABAAAAEwABACEAIgADABEAAAAaAAIAAgAAAAIJrQAAAAEAEgAA" + + "AAYAAQAAABQAIwAAAAQAAQAkACUAAAACACYAAQAnACgAAQARAAAAGgABAAIAAAACA6wAAAABABIA" + + "AAAGAAEAAAAVAAEAKQAqAAEAEQAAABoAAQABAAAAAgOsAAAAAQASAAAABgABAAAAFgABACsALAAB" + + "ABEAAAAbAAEAAQAAAAMSBbAAAAABABIAAAAGAAEAAAAXAAgALQAQAAEAEQAAAB0AAQAAAAAABQGz" + + "AAaxAAAAAQASAAAABgABAAAABwABAC4AAAACAC8="); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQCvAoivSJqk6GdYOgJmvrM/b2/flxhw99q8BwAAcAAAAHhWNBIAAAAAAAAAAPgGAAAq" + + "AAAAcAAAAA0AAAAYAQAADQAAAEwBAAADAAAA6AEAAA8AAAAAAgAAAQAAAHgCAAAkBQAAmAIAACoE" + + "AAA4BAAAPQQAAEcEAABPBAAAUwQAAFoEAABdBAAAYAQAAGQEAABoBAAAawQAAG8EAACOBAAAqgQA" + + "AL4EAADSBAAA6QQAAAMFAAAmBQAASQUAAGcFAACGBQAAmQUAALIFAAC1BQAAuQUAAL0FAADABQAA" + + "xAUAANgFAADfBQAA5wUAAPIFAAD8BQAABwYAABIGAAAWBgAAHgYAACkGAAA2BgAAQAYAAAYAAAAH" + + "AAAADAAAAA0AAAAOAAAADwAAABAAAAARAAAAEgAAABMAAAAVAAAAGAAAABsAAAAGAAAAAAAAAAAA" + + "AAAHAAAAAQAAAAAAAAAIAAAAAQAAAAQEAAAJAAAAAQAAAAwEAAAJAAAAAQAAABQEAAAKAAAABQAA" + + "AAAAAAAKAAAABwAAAAAAAAALAAAABwAAAAQEAAAYAAAACwAAAAAAAAAZAAAACwAAAAQEAAAaAAAA" + + "CwAAABwEAAAbAAAADAAAAAAAAAAcAAAADAAAACQEAAAHAAcABQAAAAcADAAjAAAABwABACkAAAAE" + + "AAgAAwAAAAcACAACAAAABwAIAAMAAAAHAAkAAwAAAAcABgAeAAAABwAMAB8AAAAHAAEAIAAAAAcA" + + "AAAhAAAABwAKACIAAAAHAAsAIwAAAAcABwAkAAAABwACACUAAAAHAAMAJgAAAAcABAAnAAAABwAF" + + "ACgAAAAHAAAAEQAAAAQAAAAAAAAAFgAAAOwDAACtBgAAAAAAAAIAAACVBgAApQYAAAEAAAAAAAAA" + + "RwYAAAQAAAASAGkAAAAOAAMAAQABAAAATQYAAAsAAABwEAAAAgASAFwgAQAWAAAAWiACAA4AAAAD" + + "AAMAAQAAAFIGAAAEAAAAcBACAAAADgABAAAAAAAAAFgGAAACAAAAEgARAAMAAgAAAAAAXQYAAAIA" + + "AAASABEAAwACAAAAAABjBgAAAgAAABIADwADAAEAAAAAAGkGAAADAAAAFgAAABAAAAACAAEAAAAA" + + "AG4GAAACAAAAEgAPAAIAAgAAAAAAcwYAAAEAAAAOAAAAAgABAAAAAAB5BgAAAgAAABIADwAFAAMA" + + "AAAAAH4GAAADAAAAFgAAABAAAAAEAAIAAAAAAIQGAAADAAAAFgAAABAAAAAEAAIAAAAAAIoGAAAD" + + "AAAAFgAAABAAAAACAAEAAAAAAJAGAAAEAAAAGwAXAAAAEQAAAAAAAAAAAAEAAAAAAAAADQAAAJgC" + + "AAABAAAAAQAAAAEAAAAJAAAAAQAAAAoAAAABAAAACAAAAAEAAAAEAAw8VFg7PjspSl5UWDsAAzxY" + + "OgAIPGNsaW5pdD4ABjxpbml0PgACPigABUVNUFRZAAFJAAFKAAJKSgACSkwAAUwAAkxKAB1MZGFs" + + "dmlrL2Fubm90YXRpb24vU2lnbmF0dXJlOwAaTGRhbHZpay9hbm5vdGF0aW9uL1Rocm93czsAEkxq" + + "YXZhL2xhbmcvT2JqZWN0OwASTGphdmEvbGFuZy9TdHJpbmc7ABVMamF2YS9sYW5nL1Rocm93YWJs" + + "ZTsAGExqYXZhL3V0aWwvT3B0aW9uYWxMb25nOwAhTGphdmEvdXRpbC9mdW5jdGlvbi9Mb25nQ29u" + + "c3VtZXI7ACFMamF2YS91dGlsL2Z1bmN0aW9uL0xvbmdTdXBwbGllcjsAHExqYXZhL3V0aWwvZnVu" + + "Y3Rpb24vU3VwcGxpZXIAHUxqYXZhL3V0aWwvZnVuY3Rpb24vU3VwcGxpZXI7ABFPcHRpb25hbExv" + + "bmcuamF2YQAXUmVkZWZpbmVkIE9wdGlvbmFsTG9uZyEAAVYAAlZKAAJWTAABWgACWkwAEmVtaXR0" + + "ZXI6IGphY2stNC4yMgAFZW1wdHkABmVxdWFscwAJZ2V0QXNMb25nAAhoYXNoQ29kZQAJaWZQcmVz" + + "ZW50AAlpc1ByZXNlbnQAAm9mAAZvckVsc2UACW9yRWxzZUdldAALb3JFbHNlVGhyb3cACHRvU3Ry" + + "aW5nAAV2YWx1ZQAHAAcOOQALAAcOAAwBAAcOAA0ABw4ADgEABw4AFQEABw4ADwAHDgAWAAcOABEB" + + "AAcOABAABw4AEgEABw4AEwEABw4AFAEABw4AFwAHDgACAgEpHAUXARcQFwQXFBcAAgMBKRwBGAYB" + + "AgUJABoBEgESAYiABKQFAYKABLwFAYKABOQFAQn8BQYJkAYFAaQGAQG4BgEB0AYBAeQGAQH4BgIB" + + "jAcBAaQHAQG8BwEB1AcAAAAQAAAAAAAAAAEAAAAAAAAAAQAAACoAAABwAAAAAgAAAA0AAAAYAQAA" + + "AwAAAA0AAABMAQAABAAAAAMAAADoAQAABQAAAA8AAAAAAgAABgAAAAEAAAB4AgAAAxAAAAEAAACY" + + "AgAAASAAAA4AAACkAgAABiAAAAEAAADsAwAAARAAAAUAAAAEBAAAAiAAACoAAAAqBAAAAyAAAA4A" + + "AABHBgAABCAAAAIAAACVBgAAACAAAAEAAACtBgAAABAAAAEAAAD4BgAA"); + + public static void main(String[] args) { + // OptionalLong is a class that is unlikely to be used by the time this test starts and is not + // likely to be changed in any meaningful way in the future. + OptionalLong ol = OptionalLong.of(0xDEADBEEF); + System.out.println("ol.toString() -> '" + ol.toString() + "'"); + System.out.println("Redefining OptionalLong!"); + doCommonClassRedefinition(OptionalLong.class, CLASS_BYTES, DEX_BYTES); + System.out.println("ol.toString() -> '" + ol.toString() + "'"); + } + + // Transforms the class + private static native void doCommonClassRedefinition(Class<?> target, + byte[] class_file, + byte[] dex_file); +} diff --git a/test/940-recursive-obsolete/build b/test/940-recursive-obsolete/build new file mode 100755 index 0000000000..898e2e54a2 --- /dev/null +++ b/test/940-recursive-obsolete/build @@ -0,0 +1,17 @@ +#!/bin/bash +# +# Copyright 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. + +./default-build "$@" --experimental agents diff --git a/test/940-recursive-obsolete/expected.txt b/test/940-recursive-obsolete/expected.txt new file mode 100644 index 0000000000..18ffc25d8a --- /dev/null +++ b/test/940-recursive-obsolete/expected.txt @@ -0,0 +1,21 @@ +hello2 +hello1 +Not doing anything here +hello0 +goodbye0 +goodbye1 +goodbye2 +hello2 +hello1 +transforming calling function +Hello0 - transformed +Goodbye0 - transformed +goodbye1 +goodbye2 +Hello2 - transformed +Hello1 - transformed +Not doing anything here +Hello0 - transformed +Goodbye0 - transformed +Goodbye1 - transformed +Goodbye2 - transformed diff --git a/test/940-recursive-obsolete/info.txt b/test/940-recursive-obsolete/info.txt new file mode 100644 index 0000000000..c8b892cedd --- /dev/null +++ b/test/940-recursive-obsolete/info.txt @@ -0,0 +1 @@ +Tests basic obsolete method support diff --git a/test/940-recursive-obsolete/run b/test/940-recursive-obsolete/run new file mode 100755 index 0000000000..c6e62ae6cd --- /dev/null +++ b/test/940-recursive-obsolete/run @@ -0,0 +1,17 @@ +#!/bin/bash +# +# Copyright 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. + +./default-run "$@" --jvmti diff --git a/test/940-recursive-obsolete/src/Main.java b/test/940-recursive-obsolete/src/Main.java new file mode 100644 index 0000000000..3766906a89 --- /dev/null +++ b/test/940-recursive-obsolete/src/Main.java @@ -0,0 +1,89 @@ +/* + * 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; + +public class Main { + + // class Transform { + // public void sayHi(int recur, Runnable r) { + // System.out.println("Hello" + recur + " - transformed"); + // if (recur == 1) { + // r.run(); + // sayHi(recur - 1, r); + // } else if (recur != 0) { + // sayHi(recur - 1, r); + // } + // System.out.println("Goodbye" + recur + " - transformed"); + // } + // } + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQANwoADwAZCQAaABsHABwKAAMAGQgAHQoAAwAeCgADAB8IACAKAAMAIQoAIgAjCwAk" + + "ACUKAA4AJggAJwcAKAcAKQEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUB" + + "AAVzYXlIaQEAGChJTGphdmEvbGFuZy9SdW5uYWJsZTspVgEADVN0YWNrTWFwVGFibGUBAApTb3Vy" + + "Y2VGaWxlAQAOVHJhbnNmb3JtLmphdmEMABAAEQcAKgwAKwAsAQAXamF2YS9sYW5nL1N0cmluZ0J1" + + "aWxkZXIBAAVIZWxsbwwALQAuDAAtAC8BAA4gLSB0cmFuc2Zvcm1lZAwAMAAxBwAyDAAzADQHADUM" + + "ADYAEQwAFAAVAQAHR29vZGJ5ZQEACVRyYW5zZm9ybQEAEGphdmEvbGFuZy9PYmplY3QBABBqYXZh" + + "L2xhbmcvU3lzdGVtAQADb3V0AQAVTGphdmEvaW8vUHJpbnRTdHJlYW07AQAGYXBwZW5kAQAtKExq" + + "YXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7AQAcKEkpTGphdmEvbGFu" + + "Zy9TdHJpbmdCdWlsZGVyOwEACHRvU3RyaW5nAQAUKClMamF2YS9sYW5nL1N0cmluZzsBABNqYXZh" + + "L2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEAEmphdmEv" + + "bGFuZy9SdW5uYWJsZQEAA3J1bgAgAA4ADwAAAAAAAgAAABAAEQABABIAAAAdAAEAAQAAAAUqtwAB" + + "sQAAAAEAEwAAAAYAAQAAAAEAAQAUABUAAQASAAAAnQADAAMAAABfsgACuwADWbcABBIFtgAGG7YA" + + "BxIItgAGtgAJtgAKGwSgABQsuQALAQAqGwRkLLYADKcADxuZAAsqGwRkLLYADLIAArsAA1m3AAQS" + + "DbYABhu2AAcSCLYABrYACbYACrEAAAACABMAAAAiAAgAAAADAB4ABAAjAAUAKQAGADQABwA4AAgA" + + "QAAKAF4ACwAWAAAABAACNAsAAQAXAAAAAgAY"); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQA3pkIgnymz2/eri+mp2dyZo3jolQmaRPKEBAAAcAAAAHhWNBIAAAAAAAAAAOQDAAAa" + + "AAAAcAAAAAkAAADYAAAABgAAAPwAAAABAAAARAEAAAkAAABMAQAAAQAAAJQBAADQAgAAtAEAAJwC" + + "AACsAgAAtAIAAL0CAADEAgAAxwIAAMoCAADOAgAA0gIAAN8CAAD2AgAACgMAACADAAA0AwAATwMA" + + "AGMDAABzAwAAdgMAAHsDAAB/AwAAhwMAAJsDAACgAwAAqQMAAK4DAAC1AwAABAAAAAgAAAAJAAAA" + + "CgAAAAsAAAAMAAAADQAAAA4AAAAQAAAABQAAAAUAAAAAAAAABgAAAAYAAACEAgAABwAAAAYAAACM" + + "AgAAEAAAAAgAAAAAAAAAEQAAAAgAAACUAgAAEgAAAAgAAACMAgAABwACABUAAAABAAMAAQAAAAEA" + + "BAAYAAAAAgAFABYAAAADAAMAAQAAAAQAAwAXAAAABgADAAEAAAAGAAEAEwAAAAYAAgATAAAABgAA" + + "ABkAAAABAAAAAAAAAAMAAAAAAAAADwAAAAAAAADWAwAAAAAAAAEAAQABAAAAvwMAAAQAAABwEAMA" + + "AAAOAAYAAwADAAAAxAMAAFQAAABiAAAAIgEGAHAQBQABABsCAwAAAG4gBwAhAAwBbiAGAEEADAEb" + + "AgAAAABuIAcAIQAMAW4QCAABAAwBbiACABAAEhAzBCsAchAEAAUA2AAE/24wAQADBWIAAAAiAQYA" + + "cBAFAAEAGwICAAAAbiAHACEADAFuIAYAQQAMARsCAAAAAG4gBwAhAAwBbhAIAAEADAFuIAIAEAAO" + + "ADgE3//YAAT/bjABAAMFKNgBAAAAAAAAAAEAAAAFAAAAAgAAAAAABAAOIC0gdHJhbnNmb3JtZWQA" + + "Bjxpbml0PgAHR29vZGJ5ZQAFSGVsbG8AAUkAAUwAAkxJAAJMTAALTFRyYW5zZm9ybTsAFUxqYXZh" + + "L2lvL1ByaW50U3RyZWFtOwASTGphdmEvbGFuZy9PYmplY3Q7ABRMamF2YS9sYW5nL1J1bm5hYmxl" + + "OwASTGphdmEvbGFuZy9TdHJpbmc7ABlMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7ABJMamF2YS9s" + + "YW5nL1N5c3RlbTsADlRyYW5zZm9ybS5qYXZhAAFWAANWSUwAAlZMAAZhcHBlbmQAEmVtaXR0ZXI6" + + "IGphY2stNC4yNAADb3V0AAdwcmludGxuAANydW4ABXNheUhpAAh0b1N0cmluZwABAAcOAAMCAAAH" + + "DgEgDzw8XQEgDxktAAAAAQEAgIAEtAMBAcwDDQAAAAAAAAABAAAAAAAAAAEAAAAaAAAAcAAAAAIA" + + "AAAJAAAA2AAAAAMAAAAGAAAA/AAAAAQAAAABAAAARAEAAAUAAAAJAAAATAEAAAYAAAABAAAAlAEA" + + "AAEgAAACAAAAtAEAAAEQAAADAAAAhAIAAAIgAAAaAAAAnAIAAAMgAAACAAAAvwMAAAAgAAABAAAA" + + "1gMAAAAQAAABAAAA5AMAAA=="); + + public static void main(String[] args) { + doTest(new Transform()); + } + + public static void doTest(Transform t) { + t.sayHi(2, () -> { System.out.println("Not doing anything here"); }); + t.sayHi(2, () -> { + System.out.println("transforming calling function"); + doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); + }); + t.sayHi(2, () -> { System.out.println("Not doing anything here"); }); + } + + // Transforms the class + private static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); +} diff --git a/test/940-recursive-obsolete/src/Transform.java b/test/940-recursive-obsolete/src/Transform.java new file mode 100644 index 0000000000..97522cddf6 --- /dev/null +++ b/test/940-recursive-obsolete/src/Transform.java @@ -0,0 +1,28 @@ +/* + * 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. + */ + +class Transform { + public void sayHi(int recur, Runnable r) { + System.out.println("hello" + recur); + if (recur == 1) { + r.run(); + sayHi(recur - 1, r); + } else if (recur != 0) { + sayHi(recur - 1, r); + } + System.out.println("goodbye" + recur); + } +} diff --git a/test/941-recurive-obsolete-jit/build b/test/941-recurive-obsolete-jit/build new file mode 100755 index 0000000000..898e2e54a2 --- /dev/null +++ b/test/941-recurive-obsolete-jit/build @@ -0,0 +1,17 @@ +#!/bin/bash +# +# Copyright 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. + +./default-build "$@" --experimental agents diff --git a/test/941-recurive-obsolete-jit/expected.txt b/test/941-recurive-obsolete-jit/expected.txt new file mode 100644 index 0000000000..086f7b03dc --- /dev/null +++ b/test/941-recurive-obsolete-jit/expected.txt @@ -0,0 +1,22 @@ +hello2 +hello1 +Not doing anything here +hello0 +goodbye0 +goodbye1 +goodbye2 +hello2 +hello1 +transforming calling function +Hello0 - transformed +Goodbye0 - transformed +goodbye1 +goodbye2 +Hello2 - transformed +Hello1 - transformed +Not doing anything here +Hello0 - transformed +Goodbye0 - transformed +Goodbye1 - transformed +Goodbye2 - transformed + diff --git a/test/941-recurive-obsolete-jit/info.txt b/test/941-recurive-obsolete-jit/info.txt new file mode 100644 index 0000000000..c8b892cedd --- /dev/null +++ b/test/941-recurive-obsolete-jit/info.txt @@ -0,0 +1 @@ +Tests basic obsolete method support diff --git a/test/941-recurive-obsolete-jit/run b/test/941-recurive-obsolete-jit/run new file mode 100755 index 0000000000..c6e62ae6cd --- /dev/null +++ b/test/941-recurive-obsolete-jit/run @@ -0,0 +1,17 @@ +#!/bin/bash +# +# Copyright 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. + +./default-run "$@" --jvmti diff --git a/test/941-recurive-obsolete-jit/src/Main.java b/test/941-recurive-obsolete-jit/src/Main.java new file mode 100644 index 0000000000..f6d6416b55 --- /dev/null +++ b/test/941-recurive-obsolete-jit/src/Main.java @@ -0,0 +1,155 @@ +/* + * 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 { + + // import java.util.function.Consumer; + // class Transform { + // public void sayHi(int recur, Consumer<String> reporter, Runnable r) { + // reporter.accept("Hello" + recur + " - transformed"); + // if (recur == 1) { + // r.run(); + // sayHi(recur - 1, reporter, r); + // } else if (recur != 0) { + // sayHi(recur - 1, reporter, r); + // } + // reporter.accept("Goodbye" + recur + " - transformed"); + // } + // } + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAMwoADgAaBwAbCgACABoIABwKAAIAHQoAAgAeCAAfCgACACALACEAIgsAIwAkCgAN" + + "ACUIACYHACcHACgBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQAFc2F5" + + "SGkBADUoSUxqYXZhL3V0aWwvZnVuY3Rpb24vQ29uc3VtZXI7TGphdmEvbGFuZy9SdW5uYWJsZTsp" + + "VgEADVN0YWNrTWFwVGFibGUBAAlTaWduYXR1cmUBAEkoSUxqYXZhL3V0aWwvZnVuY3Rpb24vQ29u" + + "c3VtZXI8TGphdmEvbGFuZy9TdHJpbmc7PjtMamF2YS9sYW5nL1J1bm5hYmxlOylWAQAKU291cmNl" + + "RmlsZQEADlRyYW5zZm9ybS5qYXZhDAAPABABABdqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcgEABUhl" + + "bGxvDAApACoMACkAKwEADiAtIHRyYW5zZm9ybWVkDAAsAC0HAC4MAC8AMAcAMQwAMgAQDAATABQB" + + "AAdHb29kYnllAQAJVHJhbnNmb3JtAQAQamF2YS9sYW5nL09iamVjdAEABmFwcGVuZAEALShMamF2" + + "YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwEAHChJKUxqYXZhL2xhbmcv" + + "U3RyaW5nQnVpbGRlcjsBAAh0b1N0cmluZwEAFCgpTGphdmEvbGFuZy9TdHJpbmc7AQAbamF2YS91" + + "dGlsL2Z1bmN0aW9uL0NvbnN1bWVyAQAGYWNjZXB0AQAVKExqYXZhL2xhbmcvT2JqZWN0OylWAQAS" + + "amF2YS9sYW5nL1J1bm5hYmxlAQADcnVuACAADQAOAAAAAAACAAAADwAQAAEAEQAAAB0AAQABAAAA" + + "BSq3AAGxAAAAAQASAAAABgABAAAAAgABABMAFAACABEAAACfAAQABAAAAGEsuwACWbcAAxIEtgAF" + + "G7YABhIHtgAFtgAIuQAJAgAbBKAAFS25AAoBACobBGQsLbYAC6cAEBuZAAwqGwRkLC22AAssuwAC" + + "WbcAAxIMtgAFG7YABhIHtgAFtgAIuQAJAgCxAAAAAgASAAAAIgAIAAAABAAeAAUAIwAGACkABwA1" + + "AAgAOQAJAEIACwBgAAwAFQAAAAQAAjUMABYAAAACABcAAQAYAAAAAgAZ"); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQA7uevryhDgvad3G3EACTdspZGfNKv2i3kkBQAAcAAAAHhWNBIAAAAAAAAAAGwEAAAf" + + "AAAAcAAAAAkAAADsAAAABgAAABABAAAAAAAAAAAAAAkAAABYAQAAAQAAAKABAABkAwAAwAEAAMoC" + + "AADaAgAA3gIAAOICAADlAgAA7QIAAPECAAD6AgAAAQMAAAQDAAAHAwAACwMAAA8DAAAcAwAAOwMA" + + "AE8DAABlAwAAeQMAAJQDAACyAwAA0QMAAOEDAADkAwAA6gMAAO4DAAD2AwAA/gMAABIEAAAXBAAA" + + "HgQAACgEAAAIAAAADAAAAA0AAAAOAAAADwAAABAAAAARAAAAEwAAABUAAAAJAAAABQAAAAAAAAAK" + + "AAAABgAAAKgCAAALAAAABgAAALACAAAVAAAACAAAAAAAAAAWAAAACAAAALgCAAAXAAAACAAAAMQC" + + "AAABAAMABAAAAAEABAAcAAAAAwADAAQAAAAEAAMAGwAAAAYAAwAEAAAABgABABkAAAAGAAIAGQAA" + + "AAYAAAAdAAAABwAFABgAAAABAAAAAAAAAAMAAAAAAAAAFAAAAJACAABbBAAAAAAAAAEAAABHBAAA" + + "AQABAAEAAAAvBAAABAAAAHAQAgAAAA4ABgAEAAQAAAA0BAAAUAAAACIABgBwEAQAAAAbAQcAAABu" + + "IAYAEAAMAG4gBQAwAAwAGwEAAAAAbiAGABAADABuEAcAAAAMAHIgCAAEABIQMwMpAHIQAwAFANgA" + + "A/9uQAEAAlQiAAYAcBAEAAAAGwEGAAAAbiAGABAADABuIAUAMAAMABsBAAAAAG4gBgAQAAwAbhAH" + + "AAAADAByIAgABAAOADgD4f/YAAP/bkABAAJUKNoAAAAAAAAAAAEAAAAAAAAAAQAAAMABAAABAAAA" + + "AAAAAAEAAAAFAAAAAwAAAAAABwAEAAAAAQAAAAMADiAtIHRyYW5zZm9ybWVkAAIoSQACKVYAATwA" + + "Bjxpbml0PgACPjsAB0dvb2RieWUABUhlbGxvAAFJAAFMAAJMSQACTEwAC0xUcmFuc2Zvcm07AB1M" + + "ZGFsdmlrL2Fubm90YXRpb24vU2lnbmF0dXJlOwASTGphdmEvbGFuZy9PYmplY3Q7ABRMamF2YS9s" + + "YW5nL1J1bm5hYmxlOwASTGphdmEvbGFuZy9TdHJpbmc7ABlMamF2YS9sYW5nL1N0cmluZ0J1aWxk" + + "ZXI7ABxMamF2YS91dGlsL2Z1bmN0aW9uL0NvbnN1bWVyAB1MamF2YS91dGlsL2Z1bmN0aW9uL0Nv" + + "bnN1bWVyOwAOVHJhbnNmb3JtLmphdmEAAVYABFZJTEwAAlZMAAZhY2NlcHQABmFwcGVuZAASZW1p" + + "dHRlcjogamFjay00LjI0AANydW4ABXNheUhpAAh0b1N0cmluZwAFdmFsdWUAAgAHDgAEAwAAAAcO" + + "AR4PPDxdAR4PGS0AAgIBHhwHFwEXEhcDFxAXBRcPFwIAAAEBAICABMgDAQHgAwAAAA8AAAAAAAAA" + + "AQAAAAAAAAABAAAAHwAAAHAAAAACAAAACQAAAOwAAAADAAAABgAAABABAAAFAAAACQAAAFgBAAAG" + + "AAAAAQAAAKABAAADEAAAAQAAAMABAAABIAAAAgAAAMgBAAAGIAAAAQAAAJACAAABEAAABAAAAKgC" + + "AAACIAAAHwAAAMoCAAADIAAAAgAAAC8EAAAEIAAAAQAAAEcEAAAAIAAAAQAAAFsEAAAAEAAAAQAA" + + "AGwEAAA="); + + // 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) { + 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; + // 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); + } 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)) { + // 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"); + // 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); +} diff --git a/test/941-recurive-obsolete-jit/src/Transform.java b/test/941-recurive-obsolete-jit/src/Transform.java new file mode 100644 index 0000000000..e6a913a391 --- /dev/null +++ b/test/941-recurive-obsolete-jit/src/Transform.java @@ -0,0 +1,29 @@ +/* + * 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.function.Consumer; +class Transform { + public void sayHi(int recur, Consumer<String> c, Runnable r) { + c.accept("hello" + recur); + if (recur == 1) { + r.run(); + sayHi(recur - 1, c, r); + } else if (recur != 0) { + sayHi(recur - 1, c, r); + } + c.accept("goodbye" + recur); + } +} diff --git a/test/942-private-recursive/build b/test/942-private-recursive/build new file mode 100755 index 0000000000..898e2e54a2 --- /dev/null +++ b/test/942-private-recursive/build @@ -0,0 +1,17 @@ +#!/bin/bash +# +# Copyright 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. + +./default-build "$@" --experimental agents diff --git a/test/942-private-recursive/expected.txt b/test/942-private-recursive/expected.txt new file mode 100644 index 0000000000..18ffc25d8a --- /dev/null +++ b/test/942-private-recursive/expected.txt @@ -0,0 +1,21 @@ +hello2 +hello1 +Not doing anything here +hello0 +goodbye0 +goodbye1 +goodbye2 +hello2 +hello1 +transforming calling function +Hello0 - transformed +Goodbye0 - transformed +goodbye1 +goodbye2 +Hello2 - transformed +Hello1 - transformed +Not doing anything here +Hello0 - transformed +Goodbye0 - transformed +Goodbye1 - transformed +Goodbye2 - transformed diff --git a/test/942-private-recursive/info.txt b/test/942-private-recursive/info.txt new file mode 100644 index 0000000000..c8b892cedd --- /dev/null +++ b/test/942-private-recursive/info.txt @@ -0,0 +1 @@ +Tests basic obsolete method support diff --git a/test/942-private-recursive/run b/test/942-private-recursive/run new file mode 100755 index 0000000000..c6e62ae6cd --- /dev/null +++ b/test/942-private-recursive/run @@ -0,0 +1,17 @@ +#!/bin/bash +# +# Copyright 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. + +./default-run "$@" --jvmti diff --git a/test/942-private-recursive/src/Main.java b/test/942-private-recursive/src/Main.java new file mode 100644 index 0000000000..8cbab7bac3 --- /dev/null +++ b/test/942-private-recursive/src/Main.java @@ -0,0 +1,94 @@ +/* + * 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; + +public class Main { + + // class Transform { + // public void sayHi(int recur, Runnable r) { + // privateSayHi(recur, r); + // } + // private void privateSayHi(int recur, Runnable r) { + // System.out.println("Hello" + recur + " - transformed"); + // if (recur == 1) { + // r.run(); + // privateSayHi(recur - 1, r); + // } else if (recur != 0) { + // privateSayHi(recur - 1, r); + // } + // System.out.println("Goodbye" + recur + " - transformed"); + // } + // } + private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( + "yv66vgAAADQAOAoADwAaCgAOABsJABwAHQcAHgoABAAaCAAfCgAEACAKAAQAIQgAIgoABAAjCgAk" + + "ACULACYAJwgAKAcAKQcAKgEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUB" + + "AAVzYXlIaQEAGChJTGphdmEvbGFuZy9SdW5uYWJsZTspVgEADHByaXZhdGVTYXlIaQEADVN0YWNr" + + "TWFwVGFibGUBAApTb3VyY2VGaWxlAQAOVHJhbnNmb3JtLmphdmEMABAAEQwAFgAVBwArDAAsAC0B" + + "ABdqYXZhL2xhbmcvU3RyaW5nQnVpbGRlcgEABUhlbGxvDAAuAC8MAC4AMAEADiAtIHRyYW5zZm9y" + + "bWVkDAAxADIHADMMADQANQcANgwANwARAQAHR29vZGJ5ZQEACVRyYW5zZm9ybQEAEGphdmEvbGFu" + + "Zy9PYmplY3QBABBqYXZhL2xhbmcvU3lzdGVtAQADb3V0AQAVTGphdmEvaW8vUHJpbnRTdHJlYW07" + + "AQAGYXBwZW5kAQAtKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7" + + "AQAcKEkpTGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwEACHRvU3RyaW5nAQAUKClMamF2YS9sYW5n" + + "L1N0cmluZzsBABNqYXZhL2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0" + + "cmluZzspVgEAEmphdmEvbGFuZy9SdW5uYWJsZQEAA3J1bgAgAA4ADwAAAAAAAwAAABAAEQABABIA" + + "AAAdAAEAAQAAAAUqtwABsQAAAAEAEwAAAAYAAQAAAAEAAQAUABUAAQASAAAAIwADAAMAAAAHKhss" + + "twACsQAAAAEAEwAAAAoAAgAAAAMABgAEAAIAFgAVAAEAEgAAAJ0AAwADAAAAX7IAA7sABFm3AAUS" + + "BrYABxu2AAgSCbYAB7YACrYACxsEoAAULLkADAEAKhsEZCy3AAKnAA8bmQALKhsEZCy3AAKyAAO7" + + "AARZtwAFEg22AAcbtgAIEgm2AAe2AAq2AAuxAAAAAgATAAAAIgAIAAAABgAeAAcAIwAIACkACQA0" + + "AAoAOAALAEAADQBeAA4AFwAAAAQAAjQLAAEAGAAAAAIAGQ=="); + private static final byte[] DEX_BYTES = Base64.getDecoder().decode( + "ZGV4CjAzNQBQqwVIiZvIuS8j1HDurKbXZEV62Mnug5PEBAAAcAAAAHhWNBIAAAAAAAAAACQEAAAb" + + "AAAAcAAAAAkAAADcAAAABgAAAAABAAABAAAASAEAAAoAAABQAQAAAQAAAKABAAAEAwAAwAEAAMAC" + + "AADQAgAA2AIAAOECAADoAgAA6wIAAO4CAADyAgAA9gIAAAMDAAAaAwAALgMAAEQDAABYAwAAcwMA" + + "AIcDAACXAwAAmgMAAJ8DAACjAwAAqwMAAL8DAADEAwAAzQMAANsDAADgAwAA5wMAAAQAAAAIAAAA" + + "CQAAAAoAAAALAAAADAAAAA0AAAAOAAAAEAAAAAUAAAAFAAAAAAAAAAYAAAAGAAAAqAIAAAcAAAAG" + + "AAAAsAIAABAAAAAIAAAAAAAAABEAAAAIAAAAuAIAABIAAAAIAAAAsAIAAAcAAgAVAAAAAQADAAEA" + + "AAABAAQAFwAAAAEABAAZAAAAAgAFABYAAAADAAMAAQAAAAQAAwAYAAAABgADAAEAAAAGAAEAEwAA" + + "AAYAAgATAAAABgAAABoAAAABAAAAAAAAAAMAAAAAAAAADwAAAAAAAAAQBAAAAAAAAAEAAQABAAAA" + + "8QMAAAQAAABwEAQAAAAOAAYAAwADAAAA9gMAAFQAAABiAAAAIgEGAHAQBgABABsCAwAAAG4gCAAh" + + "AAwBbiAHAEEADAEbAgAAAABuIAgAIQAMAW4QCQABAAwBbiADABAAEhAzBCsAchAFAAUA2AAE/3Aw" + + "AQADBWIAAAAiAQYAcBAGAAEAGwICAAAAbiAIACEADAFuIAcAQQAMARsCAAAAAG4gCAAhAAwBbhAJ" + + "AAEADAFuIAMAEAAOADgE3//YAAT/cDABAAMFKNgDAAMAAwAAAAgEAAAEAAAAcDABABACDgABAAAA" + + "AAAAAAEAAAAFAAAAAgAAAAAABAAOIC0gdHJhbnNmb3JtZWQABjxpbml0PgAHR29vZGJ5ZQAFSGVs" + + "bG8AAUkAAUwAAkxJAAJMTAALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwASTGph" + + "dmEvbGFuZy9PYmplY3Q7ABRMamF2YS9sYW5nL1J1bm5hYmxlOwASTGphdmEvbGFuZy9TdHJpbmc7" + + "ABlMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7ABJMamF2YS9sYW5nL1N5c3RlbTsADlRyYW5zZm9y" + + "bS5qYXZhAAFWAANWSUwAAlZMAAZhcHBlbmQAEmVtaXR0ZXI6IGphY2stNC4yNAADb3V0AAdwcmlu" + + "dGxuAAxwcml2YXRlU2F5SGkAA3J1bgAFc2F5SGkACHRvU3RyaW5nAAEABw4ABgIAAAcOASAPPDxd" + + "ASAPGS0AAwIAAAcOPAAAAAIBAICABMADAQLYAwIBkAUAAA0AAAAAAAAAAQAAAAAAAAABAAAAGwAA" + + "AHAAAAACAAAACQAAANwAAAADAAAABgAAAAABAAAEAAAAAQAAAEgBAAAFAAAACgAAAFABAAAGAAAA" + + "AQAAAKABAAABIAAAAwAAAMABAAABEAAAAwAAAKgCAAACIAAAGwAAAMACAAADIAAAAwAAAPEDAAAA" + + "IAAAAQAAABAEAAAAEAAAAQAAACQEAAA="); + + public static void main(String[] args) { + doTest(new Transform()); + } + + public static void doTest(Transform t) { + t.sayHi(2, () -> { System.out.println("Not doing anything here"); }); + t.sayHi(2, () -> { + System.out.println("transforming calling function"); + doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); + }); + t.sayHi(2, () -> { System.out.println("Not doing anything here"); }); + } + + // Transforms the class + private static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); +} diff --git a/test/942-private-recursive/src/Transform.java b/test/942-private-recursive/src/Transform.java new file mode 100644 index 0000000000..7714326066 --- /dev/null +++ b/test/942-private-recursive/src/Transform.java @@ -0,0 +1,32 @@ +/* + * 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. + */ + +class Transform { + private void privateSayHi(int recur, Runnable r) { + System.out.println("hello" + recur); + if (recur == 1) { + r.run(); + privateSayHi(recur - 1, r); + } else if (recur != 0) { + privateSayHi(recur - 1, r); + } + System.out.println("goodbye" + recur); + } + + public void sayHi(int recur, Runnable r) { + privateSayHi(recur, r); + } +} diff --git a/test/943-private-recursive-jit/build b/test/943-private-recursive-jit/build new file mode 100755 index 0000000000..898e2e54a2 --- /dev/null +++ b/test/943-private-recursive-jit/build @@ -0,0 +1,17 @@ +#!/bin/bash +# +# Copyright 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. + +./default-build "$@" --experimental agents diff --git a/test/943-private-recursive-jit/expected.txt b/test/943-private-recursive-jit/expected.txt new file mode 100644 index 0000000000..447f4a2245 --- /dev/null +++ b/test/943-private-recursive-jit/expected.txt @@ -0,0 +1,22 @@ +hello2 +hello1 +Not doing anything here +hello0 +goodbye0 +goodbye1 +goodbye2 +hello2 +hello1 +transforming calling function +hello0 - transformed +goodbye0 - transformed +goodbye1 +goodbye2 +hello2 - transformed +hello1 - transformed +Not doing anything here +hello0 - transformed +goodbye0 - transformed +goodbye1 - transformed +goodbye2 - transformed + diff --git a/test/943-private-recursive-jit/info.txt b/test/943-private-recursive-jit/info.txt new file mode 100644 index 0000000000..c8b892cedd --- /dev/null +++ b/test/943-private-recursive-jit/info.txt @@ -0,0 +1 @@ +Tests basic obsolete method support diff --git a/test/943-private-recursive-jit/run b/test/943-private-recursive-jit/run new file mode 100755 index 0000000000..c6e62ae6cd --- /dev/null +++ b/test/943-private-recursive-jit/run @@ -0,0 +1,17 @@ +#!/bin/bash +# +# Copyright 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. + +./default-run "$@" --jvmti 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); +} diff --git a/test/943-private-recursive-jit/src/Transform.java b/test/943-private-recursive-jit/src/Transform.java new file mode 100644 index 0000000000..9ec3e42544 --- /dev/null +++ b/test/943-private-recursive-jit/src/Transform.java @@ -0,0 +1,33 @@ +/* + * 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.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.accept("hello" + recur); + if (recur == 1) { + r.run(); + privateSayHi(recur - 1, reporter, r); + } else if (recur != 0) { + privateSayHi(recur - 1, reporter, r); + } + reporter.accept("goodbye" + recur); + } +} diff --git a/test/944-transform-classloaders/build b/test/944-transform-classloaders/build new file mode 100755 index 0000000000..898e2e54a2 --- /dev/null +++ b/test/944-transform-classloaders/build @@ -0,0 +1,17 @@ +#!/bin/bash +# +# Copyright 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. + +./default-build "$@" --experimental agents diff --git a/test/944-transform-classloaders/classloader.cc b/test/944-transform-classloaders/classloader.cc new file mode 100644 index 0000000000..5fbd8e11c9 --- /dev/null +++ b/test/944-transform-classloaders/classloader.cc @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2017 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. + */ + +#include "base/macros.h" +#include "jni.h" +#include "mirror/class-inl.h" +#include "openjdkjvmti/jvmti.h" +#include "ScopedLocalRef.h" + +#include "ti-agent/common_helper.h" +#include "ti-agent/common_load.h" + +namespace art { +namespace Test944TransformClassloaders { + + +extern "C" JNIEXPORT jlong JNICALL Java_Main_getDexFilePointer(JNIEnv* env, jclass, jclass klass) { + if (Runtime::Current() == nullptr) { + env->ThrowNew(env->FindClass("java/lang/Exception"), + "We do not seem to be running in ART! Unable to get dex file."); + return 0; + } + ScopedObjectAccess soa(env); + // This sequence of casts must be the same as those done in + // runtime/native/dalvik_system_DexFile.cc in order to ensure that we get the same results. + return static_cast<jlong>(reinterpret_cast<uintptr_t>( + &soa.Decode<mirror::Class>(klass)->GetDexFile())); +} + +} // namespace Test944TransformClassloaders +} // namespace art diff --git a/test/944-transform-classloaders/expected.txt b/test/944-transform-classloaders/expected.txt new file mode 100644 index 0000000000..79522479dd --- /dev/null +++ b/test/944-transform-classloaders/expected.txt @@ -0,0 +1,5 @@ +hello +hello2 +Goodbye +Goodbye2 +Passed diff --git a/test/944-transform-classloaders/info.txt b/test/944-transform-classloaders/info.txt new file mode 100644 index 0000000000..9155564d62 --- /dev/null +++ b/test/944-transform-classloaders/info.txt @@ -0,0 +1,7 @@ +Tests that redefined dex files are stored in the appropriate classloader. + +This test cannot run on the RI. + +We use reflection with setAccessible(true) to examine the private internals of +classloaders. Changes to the internal operation or definition of +dalvik.system.BaseDexClassLoader might cause this test to fail. diff --git a/test/944-transform-classloaders/run b/test/944-transform-classloaders/run new file mode 100755 index 0000000000..c6e62ae6cd --- /dev/null +++ b/test/944-transform-classloaders/run @@ -0,0 +1,17 @@ +#!/bin/bash +# +# Copyright 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. + +./default-run "$@" --jvmti diff --git a/test/944-transform-classloaders/src/CommonClassDefinition.java b/test/944-transform-classloaders/src/CommonClassDefinition.java new file mode 100644 index 0000000000..62602a02e9 --- /dev/null +++ b/test/944-transform-classloaders/src/CommonClassDefinition.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2017 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. + */ + +class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } +} diff --git a/test/944-transform-classloaders/src/Main.java b/test/944-transform-classloaders/src/Main.java new file mode 100644 index 0000000000..4911e00a70 --- /dev/null +++ b/test/944-transform-classloaders/src/Main.java @@ -0,0 +1,265 @@ +/* + * Copyright (C) 2017 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.Arrays; +import java.util.ArrayList; +import java.util.Base64; +import java.lang.reflect.*; +public class Main { + + /** + * base64 encoded class/dex file for + * class Transform { + * public void sayHi() { + * System.out.println("Goodbye"); + * } + * } + */ + private static CommonClassDefinition TRANSFORM_DEFINITION = new CommonClassDefinition( + Transform.class, + Base64.getDecoder().decode( + "yv66vgAAADQAHAoABgAOCQAPABAIABEKABIAEwcAFAcAFQEABjxpbml0PgEAAygpVgEABENvZGUB" + + "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAA5UcmFuc2Zvcm0uamF2YQwA" + + "BwAIBwAWDAAXABgBAAdHb29kYnllBwAZDAAaABsBAAlUcmFuc2Zvcm0BABBqYXZhL2xhbmcvT2Jq" + + "ZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2ph" + + "dmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACAABQAG" + + "AAAAAAACAAAABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAAEQABAAsACAAB" + + "AAkAAAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAATAAgAFAABAAwAAAACAA0="), + Base64.getDecoder().decode( + "ZGV4CjAzNQCLXSBQ5FiS3f16krSYZFF8xYZtFVp0GRXMAgAAcAAAAHhWNBIAAAAAAAAAACwCAAAO" + + "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACsAQAAIAEAAGIB" + + "AABqAQAAcwEAAIABAACXAQAAqwEAAL8BAADTAQAA4wEAAOYBAADqAQAA/gEAAAMCAAAMAgAAAgAA" + + "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAABAABAAsAAAAAAAAA" + + "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAHAAAAAAAAAB4CAAAA" + + "AAAAAQABAAEAAAATAgAABAAAAHAQAwAAAA4AAwABAAIAAAAYAgAACQAAAGIAAAAbAQEAAABuIAIA" + + "EAAOAAAAAQAAAAMABjxpbml0PgAHR29vZGJ5ZQALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50" + + "U3RyZWFtOwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xh" + + "bmcvU3lzdGVtOwAOVHJhbnNmb3JtLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTMuMzYAA291" + + "dAAHcHJpbnRsbgAFc2F5SGkAEQAHDgATAAcOhQAAAAEBAICABKACAQG4Ag0AAAAAAAAAAQAAAAAA" + + "AAABAAAADgAAAHAAAAACAAAABgAAAKgAAAADAAAAAgAAAMAAAAAEAAAAAQAAANgAAAAFAAAABAAA" + + "AOAAAAAGAAAAAQAAAAABAAABIAAAAgAAACABAAABEAAAAQAAAFwBAAACIAAADgAAAGIBAAADIAAA" + + "AgAAABMCAAAAIAAAAQAAAB4CAAAAEAAAAQAAACwCAAA=")); + + /** + * base64 encoded class/dex file for + * class Transform2 { + * public void sayHi() { + * System.out.println("Goodbye2"); + * } + * } + */ + private static CommonClassDefinition TRANSFORM2_DEFINITION = new CommonClassDefinition( + Transform2.class, + Base64.getDecoder().decode( + "yv66vgAAADQAHAoABgAOCQAPABAIABEKABIAEwcAFAcAFQEABjxpbml0PgEAAygpVgEABENvZGUB" + + "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAA9UcmFuc2Zvcm0yLmphdmEM" + + "AAcACAcAFgwAFwAYAQAIR29vZGJ5ZTIHABkMABoAGwEAClRyYW5zZm9ybTIBABBqYXZhL2xhbmcv" + + "T2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEA" + + "E2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACAA" + + "BQAGAAAAAAACAAAABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAAAQABAAsA" + + "CAABAAkAAAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAADAAgABAABAAwAAAACAA0="), + Base64.getDecoder().decode( + "ZGV4CjAzNQABX6vL8OT7aGLjbzFBEfCM9Aaz+zzGzVnQAgAAcAAAAHhWNBIAAAAAAAAAADACAAAO" + + "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACwAQAAIAEAAGIB" + + "AABqAQAAdAEAAIIBAACZAQAArQEAAMEBAADVAQAA5gEAAOkBAADtAQAAAQIAAAYCAAAPAgAAAgAA" + + "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAABAABAAsAAAAAAAAA" + + "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAHAAAAAAAAACECAAAA" + + "AAAAAQABAAEAAAAWAgAABAAAAHAQAwAAAA4AAwABAAIAAAAbAgAACQAAAGIAAAAbAQEAAABuIAIA" + + "EAAOAAAAAQAAAAMABjxpbml0PgAIR29vZGJ5ZTIADExUcmFuc2Zvcm0yOwAVTGphdmEvaW8vUHJp" + + "bnRTdHJlYW07ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEv" + + "bGFuZy9TeXN0ZW07AA9UcmFuc2Zvcm0yLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTQuMjQA" + + "A291dAAHcHJpbnRsbgAFc2F5SGkAAQAHDgADAAcOhwAAAAEBAICABKACAQG4AgANAAAAAAAAAAEA" + + "AAAAAAAAAQAAAA4AAABwAAAAAgAAAAYAAACoAAAAAwAAAAIAAADAAAAABAAAAAEAAADYAAAABQAA" + + "AAQAAADgAAAABgAAAAEAAAAAAQAAASAAAAIAAAAgAQAAARAAAAEAAABcAQAAAiAAAA4AAABiAQAA" + + "AyAAAAIAAAAWAgAAACAAAAEAAAAhAgAAABAAAAEAAAAwAgAA")); + + public static void main(String[] args) throws Exception { + doTest(); + System.out.println("Passed"); + } + + private static void checkIsInstance(Class<?> klass, Object o) throws Exception { + if (!klass.isInstance(o)) { + throw new Exception(klass + " is not the class of " + o); + } + } + + private static boolean arrayContains(long[] arr, long value) { + if (arr == null) { + return false; + } + for (int i = 0; i < arr.length; i++) { + if (arr[i] == value) { + return true; + } + } + return false; + } + + /** + * Checks that we can find the dex-file for the given class in its classloader. + * + * Throws if it fails. + */ + private static void checkDexFileInClassLoader(Class<?> klass) throws Exception { + // If all the android BCP classes were availible when compiling this test and access checks + // weren't a thing this function would be written as follows: + // + // long dexFilePtr = getDexFilePointer(klass); + // dalvik.system.BaseDexClassLoader loader = + // (dalvik.system.BaseDexClassLoader)klass.getClassLoader(); + // dalvik.system.DexPathList pathListValue = loader.pathList; + // dalvik.system.DexPathList.Element[] elementArrayValue = pathListValue.dexElements; + // int array_length = elementArrayValue.length; + // for (int i = 0; i < array_length; i++) { + // dalvik.system.DexPathList.Element curElement = elementArrayValue[i]; + // dalvik.system.DexFile curDexFile = curElement.dexFile; + // if (curDexFile == null) { + // continue; + // } + // long[] curCookie = (long[])curDexFile.mCookie; + // long[] curInternalCookie = (long[])curDexFile.mInternalCookie; + // if (arrayContains(curCookie, dexFilePtr) || arrayContains(curInternalCookie, dexFilePtr)) { + // return; + // } + // } + // throw new Exception( + // "Unable to find dex file pointer " + dexFilePtr + " in class loader for " + klass); + + // Get all the fields and classes we need by reflection. + Class<?> baseDexClassLoaderClass = Class.forName("dalvik.system.BaseDexClassLoader"); + Field pathListField = baseDexClassLoaderClass.getDeclaredField("pathList"); + + Class<?> dexPathListClass = Class.forName("dalvik.system.DexPathList"); + Field elementArrayField = dexPathListClass.getDeclaredField("dexElements"); + + Class<?> dexPathListElementClass = Class.forName("dalvik.system.DexPathList$Element"); + Field dexFileField = dexPathListElementClass.getDeclaredField("dexFile"); + + Class<?> dexFileClass = Class.forName("dalvik.system.DexFile"); + Field dexFileCookieField = dexFileClass.getDeclaredField("mCookie"); + Field dexFileInternalCookieField = dexFileClass.getDeclaredField("mInternalCookie"); + + // Make all the fields accessible + AccessibleObject.setAccessible(new AccessibleObject[] { pathListField, + elementArrayField, + dexFileField, + dexFileCookieField, + dexFileInternalCookieField }, true); + + long dexFilePtr = getDexFilePointer(klass); + + ClassLoader loader = klass.getClassLoader(); + checkIsInstance(baseDexClassLoaderClass, loader); + // DexPathList pathListValue = ((BaseDexClassLoader) loader).pathList; + Object pathListValue = pathListField.get(loader); + + checkIsInstance(dexPathListClass, pathListValue); + + // DexPathList.Element[] elementArrayValue = pathListValue.dexElements; + Object elementArrayValue = elementArrayField.get(pathListValue); + if (!elementArrayValue.getClass().isArray() || + elementArrayValue.getClass().getComponentType() != dexPathListElementClass) { + throw new Exception("elementArrayValue is not an " + dexPathListElementClass + " array!"); + } + // int array_length = elementArrayValue.length; + int array_length = Array.getLength(elementArrayValue); + for (int i = 0; i < array_length; i++) { + // DexPathList.Element curElement = elementArrayValue[i]; + Object curElement = Array.get(elementArrayValue, i); + checkIsInstance(dexPathListElementClass, curElement); + + // DexFile curDexFile = curElement.dexFile; + Object curDexFile = dexFileField.get(curElement); + if (curDexFile == null) { + continue; + } + checkIsInstance(dexFileClass, curDexFile); + + // long[] curCookie = (long[])curDexFile.mCookie; + long[] curCookie = (long[])dexFileCookieField.get(curDexFile); + // long[] curInternalCookie = (long[])curDexFile.mInternalCookie; + long[] curInternalCookie = (long[])dexFileInternalCookieField.get(curDexFile); + + if (arrayContains(curCookie, dexFilePtr) || arrayContains(curInternalCookie, dexFilePtr)) { + return; + } + } + throw new Exception( + "Unable to find dex file pointer " + dexFilePtr + " in class loader for " + klass); + } + + private static void doTest() throws Exception { + Transform t = new Transform(); + Transform2 t2 = new Transform2(); + + long initial_t1_dex = getDexFilePointer(Transform.class); + long initial_t2_dex = getDexFilePointer(Transform2.class); + if (initial_t2_dex != initial_t1_dex) { + throw new Exception("The classes " + Transform.class + " and " + Transform2.class + " " + + "have different initial dex files!"); + } + checkDexFileInClassLoader(Transform.class); + checkDexFileInClassLoader(Transform2.class); + + // Make sure they are loaded + t.sayHi(); + t2.sayHi(); + // Redefine both of the classes. + doMultiClassRedefinition(TRANSFORM_DEFINITION, TRANSFORM2_DEFINITION); + // Make sure we actually transformed them! + t.sayHi(); + t2.sayHi(); + + long final_t1_dex = getDexFilePointer(Transform.class); + long final_t2_dex = getDexFilePointer(Transform2.class); + if (final_t2_dex == final_t1_dex) { + throw new Exception("The classes " + Transform.class + " and " + Transform2.class + " " + + "have the same initial dex files!"); + } else if (final_t1_dex == initial_t1_dex) { + throw new Exception("The class " + Transform.class + " did not get a new dex file!"); + } else if (final_t2_dex == initial_t2_dex) { + throw new Exception("The class " + Transform2.class + " did not get a new dex file!"); + } + // Check to make sure the new dex files are in the class loader. + checkDexFileInClassLoader(Transform.class); + checkDexFileInClassLoader(Transform2.class); + } + + private static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + // Gets the 'long' (really a native pointer) that is stored in the ClassLoader representing the + // DexFile a class is loaded from. This is converted from the DexFile* in the same way it is done + // in runtime/native/dalvik_system_DexFile.cc + private static native long getDexFilePointer(Class<?> target); + // Transforms the classes + private static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); +} diff --git a/test/944-transform-classloaders/src/Transform.java b/test/944-transform-classloaders/src/Transform.java new file mode 100644 index 0000000000..8e8af355da --- /dev/null +++ b/test/944-transform-classloaders/src/Transform.java @@ -0,0 +1,28 @@ +/* + * 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. + */ + +class Transform { + public void sayHi() { + // Use lower 'h' to make sure the string will have a different string id + // than the transformation (the transformation code is the same except + // the actual printed String, which was making the test inacurately passing + // in JIT mode when loading the string from the dex cache, as the string ids + // of the two different strings were the same). + // We know the string ids will be different because lexicographically: + // "Goodbye" < "LTransform;" < "hello". + System.out.println("hello"); + } +} diff --git a/test/944-transform-classloaders/src/Transform2.java b/test/944-transform-classloaders/src/Transform2.java new file mode 100644 index 0000000000..eb22842184 --- /dev/null +++ b/test/944-transform-classloaders/src/Transform2.java @@ -0,0 +1,21 @@ +/* + * 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. + */ + +class Transform2 { + public void sayHi() { + System.out.println("hello2"); + } +} diff --git a/test/956-methodhandles/src/Main.java b/test/956-methodhandles/src/Main.java index f8daba6239..fc9f030559 100644 --- a/test/956-methodhandles/src/Main.java +++ b/test/956-methodhandles/src/Main.java @@ -15,6 +15,7 @@ */ import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandleInfo; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles.Lookup; import java.lang.invoke.MethodType; @@ -77,6 +78,7 @@ public class Main { testReturnValueConversions(); testVariableArity(); testVariableArity_MethodHandles_bind(); + testRevealDirect(); } public static void testfindSpecial_invokeSuperBehaviour() throws Throwable { @@ -384,6 +386,10 @@ public class Main { public String publicMethod() { return "publicMethod"; } + + public String publicVarArgsMethod(String... args) { + return "publicVarArgsMethod"; + } } public static void testUnreflects() throws Throwable { @@ -670,6 +676,13 @@ public class Main { Integer.class, MethodType.methodType(Integer.class, Integer.class)); fail("Unexpected success for non-void type for findConstructor"); } catch (NoSuchMethodException e) {} + + // Array class constructor. + try { + MethodHandle foo = MethodHandles.lookup().findConstructor( + Object[].class, MethodType.methodType(void.class)); + fail("Unexpected success for array class type for findConstructor"); + } catch (NoSuchMethodException e) {} } public static void testStringConstructors() throws Throwable { @@ -1486,4 +1499,117 @@ public class Main { fail(); } catch (WrongMethodTypeException e) {} } + + public static void testRevealDirect() throws Throwable { + // Test with a virtual method : + MethodType type = MethodType.methodType(String.class); + MethodHandle handle = MethodHandles.lookup().findVirtual( + UnreflectTester.class, "publicMethod", type); + + // Comparisons with an equivalent member obtained via reflection : + MethodHandleInfo info = MethodHandles.lookup().revealDirect(handle); + Method meth = UnreflectTester.class.getMethod("publicMethod"); + + assertEquals(MethodHandleInfo.REF_invokeVirtual, info.getReferenceKind()); + assertEquals("publicMethod", info.getName()); + assertTrue(UnreflectTester.class == info.getDeclaringClass()); + assertFalse(info.isVarArgs()); + assertEquals(meth, info.reflectAs(Method.class, MethodHandles.lookup())); + assertEquals(type, info.getMethodType()); + + // Resolution via a public lookup should fail because the method in question + // isn't public. + try { + info.reflectAs(Method.class, MethodHandles.publicLookup()); + fail(); + } catch (IllegalArgumentException expected) { + } + + // Test with a static method : + handle = MethodHandles.lookup().findStatic(UnreflectTester.class, + "publicStaticMethod", + MethodType.methodType(String.class)); + + info = MethodHandles.lookup().revealDirect(handle); + meth = UnreflectTester.class.getMethod("publicStaticMethod"); + assertEquals(MethodHandleInfo.REF_invokeStatic, info.getReferenceKind()); + assertEquals("publicStaticMethod", info.getName()); + assertTrue(UnreflectTester.class == info.getDeclaringClass()); + assertFalse(info.isVarArgs()); + assertEquals(meth, info.reflectAs(Method.class, MethodHandles.lookup())); + assertEquals(type, info.getMethodType()); + + // Test with a var-args method : + type = MethodType.methodType(String.class, String[].class); + handle = MethodHandles.lookup().findVirtual(UnreflectTester.class, + "publicVarArgsMethod", type); + + info = MethodHandles.lookup().revealDirect(handle); + meth = UnreflectTester.class.getMethod("publicVarArgsMethod", String[].class); + assertEquals(MethodHandleInfo.REF_invokeVirtual, info.getReferenceKind()); + assertEquals("publicVarArgsMethod", info.getName()); + assertTrue(UnreflectTester.class == info.getDeclaringClass()); + assertTrue(info.isVarArgs()); + assertEquals(meth, info.reflectAs(Method.class, MethodHandles.lookup())); + assertEquals(type, info.getMethodType()); + + // Test with a constructor : + Constructor cons = UnreflectTester.class.getConstructor(String.class, boolean.class); + type = MethodType.methodType(void.class, String.class, boolean.class); + handle = MethodHandles.lookup().findConstructor(UnreflectTester.class, type); + + info = MethodHandles.lookup().revealDirect(handle); + assertEquals(MethodHandleInfo.REF_newInvokeSpecial, info.getReferenceKind()); + assertEquals("<init>", info.getName()); + assertTrue(UnreflectTester.class == info.getDeclaringClass()); + assertFalse(info.isVarArgs()); + assertEquals(cons, info.reflectAs(Constructor.class, MethodHandles.lookup())); + assertEquals(type, info.getMethodType()); + + // Test with a static field : + Field field = UnreflectTester.class.getField("publicStaticField"); + + handle = MethodHandles.lookup().findStaticSetter( + UnreflectTester.class, "publicStaticField", String.class); + + info = MethodHandles.lookup().revealDirect(handle); + assertEquals(MethodHandleInfo.REF_putStatic, info.getReferenceKind()); + assertEquals("publicStaticField", info.getName()); + assertTrue(UnreflectTester.class == info.getDeclaringClass()); + assertFalse(info.isVarArgs()); + assertEquals(field, info.reflectAs(Field.class, MethodHandles.lookup())); + assertEquals(MethodType.methodType(void.class, String.class), info.getMethodType()); + + // Test with a setter on the same field, the type of the handle should change + // but everything else must remain the same. + handle = MethodHandles.lookup().findStaticGetter( + UnreflectTester.class, "publicStaticField", String.class); + info = MethodHandles.lookup().revealDirect(handle); + assertEquals(MethodHandleInfo.REF_getStatic, info.getReferenceKind()); + assertEquals(field, info.reflectAs(Field.class, MethodHandles.lookup())); + assertEquals(MethodType.methodType(String.class), info.getMethodType()); + + // Test with an instance field : + field = UnreflectTester.class.getField("publicField"); + + handle = MethodHandles.lookup().findSetter( + UnreflectTester.class, "publicField", String.class); + + info = MethodHandles.lookup().revealDirect(handle); + assertEquals(MethodHandleInfo.REF_putField, info.getReferenceKind()); + assertEquals("publicField", info.getName()); + assertTrue(UnreflectTester.class == info.getDeclaringClass()); + assertFalse(info.isVarArgs()); + assertEquals(field, info.reflectAs(Field.class, MethodHandles.lookup())); + assertEquals(MethodType.methodType(void.class, String.class), info.getMethodType()); + + // Test with a setter on the same field, the type of the handle should change + // but everything else must remain the same. + handle = MethodHandles.lookup().findGetter( + UnreflectTester.class, "publicField", String.class); + info = MethodHandles.lookup().revealDirect(handle); + assertEquals(MethodHandleInfo.REF_getField, info.getReferenceKind()); + assertEquals(field, info.reflectAs(Field.class, MethodHandles.lookup())); + assertEquals(MethodType.methodType(String.class), info.getMethodType()); + } } diff --git a/test/957-methodhandle-transforms/expected.txt b/test/957-methodhandle-transforms/expected.txt index 154051f847..cf6b5a14b5 100644 --- a/test/957-methodhandle-transforms/expected.txt +++ b/test/957-methodhandle-transforms/expected.txt @@ -47,3 +47,32 @@ a: a, b:1.0, c: 2.0, d: 3.0 a: a, b:1.0, c: 2.0, d: 3.0 a: a, b:1.0, c: 2.0 a: a, b:1.0, c: 2.0 +a: a, b:b, c: c +a: a, b:b, c: c +a: a, b:43 +a: a, b:b, c: c +a: a, b:true, c: false +a: a, b:1, c: 2 +a: a, b:a, c: b +a: a, b:3, c: 4 +a: a, b:42, c: 43 +a: a, b:100, c: 99 +a: a, b:8.9, c: 9.1 +a: a, b:6.7, c: 7.8 +a: a, b: b, c:c, d:d +a: a, b: b, c:c, d:d +a: a, b: b, c:c, d:d +a: a+b, b: c, c: d +a: a, b: b+c, c: d +a: a, b: b, c: c+d +voidFilter +a: a, b: b, c: c +voidFilter +a: a, b: b, c: c +a: foo, b:45, c:56, d:bar +a: foo, b:56, c:57, d:bar +a: foo, b:56, c:57, d:bar +a: foo, b:45, c:46, d:bar +a: c+d ,b:c ,c:d ,d:e +c+d +a: a ,b:c ,c:d ,d:e diff --git a/test/957-methodhandle-transforms/src/Main.java b/test/957-methodhandle-transforms/src/Main.java index 3271108995..b6bbe74b9c 100644 --- a/test/957-methodhandle-transforms/src/Main.java +++ b/test/957-methodhandle-transforms/src/Main.java @@ -36,6 +36,12 @@ public class Main { testInvokers(); testSpreaders_reference(); testSpreaders_primitive(); + testInvokeWithArguments(); + testAsCollector(); + testFilterArguments(); + testCollectArguments(); + testInsertArguments(); + testFoldArguments(); } public static void testThrowException() throws Throwable { @@ -1223,6 +1229,418 @@ public class Main { assertEquals(51, ret); } + public static void testInvokeWithArguments() throws Throwable { + MethodType methodType = MethodType.methodType(int.class, + new Class<?>[] { String.class, String.class, String.class }); + MethodHandle handle = MethodHandles.lookup().findStatic( + Main.class, "spreadReferences", methodType); + + Object ret = handle.invokeWithArguments(new Object[] { "a", "b", "c"}); + assertEquals(42, (int) ret); + handle.invokeWithArguments(new String[] { "a", "b", "c" }); + assertEquals(42, (int) ret); + + // Pass in an array that's too small. Should throw an IAE. + try { + handle.invokeWithArguments(new Object[] { "a", "b" }); + fail(); + } catch (IllegalArgumentException expected) { + } catch (WrongMethodTypeException expected) { + } + + // Test implicit unboxing. + MethodType methodType2 = MethodType.methodType(int.class, + new Class<?>[] { String.class, int.class }); + MethodHandle handle2 = MethodHandles.lookup().findStatic( + Main.class, "spreadReferences_Unbox", methodType2); + + ret = (int) handle2.invokeWithArguments(new Object[] { "a", 43 }); + assertEquals(43, (int) ret); + } + + public static int collectBoolean(String a, boolean[] b) { + System.out.println("a: " + a + ", b:" + b[0] + ", c: " + b[1]); + return 44; + } + + public static int collectByte(String a, byte[] b) { + System.out.println("a: " + a + ", b:" + b[0] + ", c: " + b[1]); + return 45; + } + + public static int collectChar(String a, char[] b) { + System.out.println("a: " + a + ", b:" + b[0] + ", c: " + b[1]); + return 46; + } + + public static int collectShort(String a, short[] b) { + System.out.println("a: " + a + ", b:" + b[0] + ", c: " + b[1]); + return 47; + } + + public static int collectInt(String a, int[] b) { + System.out.println("a: " + a + ", b:" + b[0] + ", c: " + b[1]); + return 48; + } + + public static int collectLong(String a, long[] b) { + System.out.println("a: " + a + ", b:" + b[0] + ", c: " + b[1]); + return 49; + } + + public static int collectFloat(String a, float[] b) { + System.out.println("a: " + a + ", b:" + b[0] + ", c: " + b[1]); + return 50; + } + + public static int collectDouble(String a, double[] b) { + System.out.println("a: " + a + ", b:" + b[0] + ", c: " + b[1]); + return 51; + } + + public static int collectCharSequence(String a, CharSequence[] b) { + System.out.println("a: " + a + ", b:" + b[0] + ", c: " + b[1]); + return 99; + } + + public static void testAsCollector() throws Throwable { + // Reference arrays. + // ------------------- + MethodHandle trailingRef = MethodHandles.lookup().findStatic( + Main.class, "collectCharSequence", + MethodType.methodType(int.class, String.class, CharSequence[].class)); + + // int[] is not convertible to CharSequence[].class. + try { + trailingRef.asCollector(int[].class, 1); + fail(); + } catch (IllegalArgumentException expected) { + } + + // Object[] is not convertible to CharSequence[].class. + try { + trailingRef.asCollector(Object[].class, 1); + fail(); + } catch (IllegalArgumentException expected) { + } + + // String[].class is convertible to CharSequence.class + MethodHandle collector = trailingRef.asCollector(String[].class, 2); + assertEquals(99, (int) collector.invoke("a", "b", "c")); + + // Too few arguments should fail with a WMTE. + try { + collector.invoke("a", "b"); + fail(); + } catch (WrongMethodTypeException expected) { + } + + // Too many arguments should fail with a WMTE. + try { + collector.invoke("a", "b", "c", "d"); + fail(); + } catch (WrongMethodTypeException expected) { + } + + // Sanity checks on other array types. + + MethodHandle target = MethodHandles.lookup().findStatic( + Main.class, "collectBoolean", + MethodType.methodType(int.class, String.class, boolean[].class)); + assertEquals(44, (int) target.asCollector(boolean[].class, 2).invoke("a", true, false)); + + target = MethodHandles.lookup().findStatic(Main.class, "collectByte", + MethodType.methodType(int.class, String.class, byte[].class)); + assertEquals(45, (int) target.asCollector(byte[].class, 2).invoke("a", (byte) 1, (byte) 2)); + + target = MethodHandles.lookup().findStatic(Main.class, "collectChar", + MethodType.methodType(int.class, String.class, char[].class)); + assertEquals(46, (int) target.asCollector(char[].class, 2).invoke("a", 'a', 'b')); + + target = MethodHandles.lookup().findStatic(Main.class, "collectShort", + MethodType.methodType(int.class, String.class, short[].class)); + assertEquals(47, (int) target.asCollector(short[].class, 2).invoke("a", (short) 3, (short) 4)); + + target = MethodHandles.lookup().findStatic(Main.class, "collectInt", + MethodType.methodType(int.class, String.class, int[].class)); + assertEquals(48, (int) target.asCollector(int[].class, 2).invoke("a", 42, 43)); + + target = MethodHandles.lookup().findStatic(Main.class, "collectLong", + MethodType.methodType(int.class, String.class, long[].class)); + assertEquals(49, (int) target.asCollector(long[].class, 2).invoke("a", 100, 99)); + + target = MethodHandles.lookup().findStatic(Main.class, "collectFloat", + MethodType.methodType(int.class, String.class, float[].class)); + assertEquals(50, (int) target.asCollector(float[].class, 2).invoke("a", 8.9f, 9.1f)); + + target = MethodHandles.lookup().findStatic(Main.class, "collectDouble", + MethodType.methodType(int.class, String.class, double[].class)); + assertEquals(51, (int) target.asCollector(double[].class, 2).invoke("a", 6.7, 7.8)); + } + + public static String filter1(char a) { + return String.valueOf(a); + } + + public static char filter2(String b) { + return b.charAt(0); + } + + public static String badFilter1(char a, char b) { + return "bad"; + } + + public static int filterTarget(String a, char b, String c, char d) { + System.out.println("a: " + a + ", b: " + b + ", c:" + c + ", d:" + d); + return 56; + } + + public static void testFilterArguments() throws Throwable { + MethodHandle filter1 = MethodHandles.lookup().findStatic( + Main.class, "filter1", MethodType.methodType(String.class, char.class)); + MethodHandle filter2 = MethodHandles.lookup().findStatic( + Main.class, "filter2", MethodType.methodType(char.class, String.class)); + + MethodHandle target = MethodHandles.lookup().findStatic( + Main.class, "filterTarget", MethodType.methodType(int.class, + String.class, char.class, String.class, char.class)); + + // In all the cases below, the values printed will be 'a', 'b', 'c', 'd'. + + // Filter arguments [0, 1] - all other arguments are passed through + // as is. + MethodHandle adapter = MethodHandles.filterArguments( + target, 0, filter1, filter2); + assertEquals(56, (int) adapter.invokeExact('a', "bXXXX", "c", 'd')); + + // Filter arguments [1, 2]. + adapter = MethodHandles.filterArguments(target, 1, filter2, filter1); + assertEquals(56, (int) adapter.invokeExact("a", "bXXXX", 'c', 'd')); + + // Filter arguments [2, 3]. + adapter = MethodHandles.filterArguments(target, 2, filter1, filter2); + assertEquals(56, (int) adapter.invokeExact("a", 'b', 'c', "dXXXXX")); + + // Try out a few error cases : + + // The return types of the filter doesn't align with the expected argument + // type of the target. + try { + adapter = MethodHandles.filterArguments(target, 2, filter2, filter1); + fail(); + } catch (IllegalArgumentException expected) { + } + + // There are more filters than arguments. + try { + adapter = MethodHandles.filterArguments(target, 3, filter2, filter1); + fail(); + } catch (IllegalArgumentException expected) { + } + + // We pass in an obviously bogus position. + try { + adapter = MethodHandles.filterArguments(target, -1, filter2, filter1); + fail(); + } catch (ArrayIndexOutOfBoundsException expected) { + } + + // We pass in a function that has more than one argument. + MethodHandle badFilter1 = MethodHandles.lookup().findStatic( + Main.class, "badFilter1", + MethodType.methodType(String.class, char.class, char.class)); + + try { + adapter = MethodHandles.filterArguments(target, 0, badFilter1, filter2); + fail(); + } catch (IllegalArgumentException expected) { + } + } + + static void voidFilter(char a, char b) { + System.out.println("voidFilter"); + } + + static String filter(char a, char b) { + return String.valueOf(a) + "+" + b; + } + + static char badFilter(char a, char b) { + return 0; + } + + static int target(String a, String b, String c) { + System.out.println("a: " + a + ", b: " + b + ", c: " + c); + return 57; + } + + public static void testCollectArguments() throws Throwable { + // Test non-void filters. + MethodHandle filter = MethodHandles.lookup().findStatic( + Main.class, "filter", + MethodType.methodType(String.class, char.class, char.class)); + + MethodHandle target = MethodHandles.lookup().findStatic( + Main.class, "target", + MethodType.methodType(int.class, String.class, String.class, String.class)); + + // Filter at position 0. + MethodHandle adapter = MethodHandles.collectArguments(target, 0, filter); + assertEquals(57, (int) adapter.invokeExact('a', 'b', "c", "d")); + + // Filter at position 1. + adapter = MethodHandles.collectArguments(target, 1, filter); + assertEquals(57, (int) adapter.invokeExact("a", 'b', 'c', "d")); + + // Filter at position 2. + adapter = MethodHandles.collectArguments(target, 2, filter); + assertEquals(57, (int) adapter.invokeExact("a", "b", 'c', 'd')); + + // Test void filters. Note that we're passing in one more argument + // than usual because the filter returns nothing - we have to invoke with + // the full set of filter args and the full set of target args. + filter = MethodHandles.lookup().findStatic(Main.class, "voidFilter", + MethodType.methodType(void.class, char.class, char.class)); + adapter = MethodHandles.collectArguments(target, 0, filter); + assertEquals(57, (int) adapter.invokeExact('a', 'b', "a", "b", "c")); + + adapter = MethodHandles.collectArguments(target, 1, filter); + assertEquals(57, (int) adapter.invokeExact("a", 'a', 'b', "b", "c")); + + // Test out a few failure cases. + filter = MethodHandles.lookup().findStatic( + Main.class, "filter", + MethodType.methodType(String.class, char.class, char.class)); + + // Bogus filter position. + try { + adapter = MethodHandles.collectArguments(target, 3, filter); + fail(); + } catch (IndexOutOfBoundsException expected) { + } + + // Mismatch in filter return type. + filter = MethodHandles.lookup().findStatic( + Main.class, "badFilter", + MethodType.methodType(char.class, char.class, char.class)); + try { + adapter = MethodHandles.collectArguments(target, 0, filter); + fail(); + } catch (IllegalArgumentException expected) { + } + } + + static int insertReceiver(String a, int b, Integer c, String d) { + System.out.println("a: " + a + ", b:" + b + ", c:" + c + ", d:" + d); + return 73; + } + + public static void testInsertArguments() throws Throwable { + MethodHandle target = MethodHandles.lookup().findStatic( + Main.class, "insertReceiver", + MethodType.methodType(int.class, + String.class, int.class, Integer.class, String.class)); + + // Basic single element array inserted at position 0. + MethodHandle adapter = MethodHandles.insertArguments( + target, 0, new Object[] { "foo" }); + assertEquals(73, (int) adapter.invokeExact(45, Integer.valueOf(56), "bar")); + + // Exercise unboxing. + adapter = MethodHandles.insertArguments( + target, 1, new Object[] { Integer.valueOf(56), 57 }); + assertEquals(73, (int) adapter.invokeExact("foo", "bar")); + + // Exercise a widening conversion. + adapter = MethodHandles.insertArguments( + target, 1, new Object[] { (short) 56, Integer.valueOf(57) }); + assertEquals(73, (int) adapter.invokeExact("foo", "bar")); + + // Insert an argument at the last position. + adapter = MethodHandles.insertArguments( + target, 3, new Object[] { "bar" }); + assertEquals(73, (int) adapter.invokeExact("foo", 45, Integer.valueOf(46))); + + // Exercise a few error cases. + + // A reference type that can't be cast to another reference type. + try { + MethodHandles.insertArguments(target, 3, new Object[] { new Object() }); + fail(); + } catch (ClassCastException expected) { + } + + // A boxed type that can't be unboxed correctly. + try { + MethodHandles.insertArguments(target, 1, new Object[] { Long.valueOf(56) }); + fail(); + } catch (ClassCastException expected) { + } + } + + public static String foldFilter(char a, char b) { + return String.valueOf(a) + "+" + b; + } + + public static void voidFoldFilter(String e, char a, char b) { + System.out.println(String.valueOf(a) + "+" + b); + } + + public static int foldTarget(String a, char b, char c, String d) { + System.out.println("a: " + a + " ,b:" + b + " ,c:" + c + " ,d:" + d); + return 89; + } + + public static void mismatchedVoidFilter(Integer a) { + } + + public static Integer mismatchedNonVoidFilter(char a, char b) { + return null; + } + + public static void testFoldArguments() throws Throwable { + // Test non-void filters. + MethodHandle filter = MethodHandles.lookup().findStatic( + Main.class, "foldFilter", + MethodType.methodType(String.class, char.class, char.class)); + + MethodHandle target = MethodHandles.lookup().findStatic( + Main.class, "foldTarget", + MethodType.methodType(int.class, String.class, + char.class, char.class, String.class)); + + // Folder with a non-void type. + MethodHandle adapter = MethodHandles.foldArguments(target, filter); + assertEquals(89, (int) adapter.invokeExact('c', 'd', "e")); + + // Folder with a void type. + filter = MethodHandles.lookup().findStatic( + Main.class, "voidFoldFilter", + MethodType.methodType(void.class, String.class, char.class, char.class)); + adapter = MethodHandles.foldArguments(target, filter); + assertEquals(89, (int) adapter.invokeExact("a", 'c', 'd', "e")); + + // Test a few erroneous cases. + + filter = MethodHandles.lookup().findStatic( + Main.class, "mismatchedVoidFilter", + MethodType.methodType(void.class, Integer.class)); + try { + adapter = MethodHandles.foldArguments(target, filter); + fail(); + } catch (IllegalArgumentException expected) { + } + + filter = MethodHandles.lookup().findStatic( + Main.class, "mismatchedNonVoidFilter", + MethodType.methodType(Integer.class, char.class, char.class)); + try { + adapter = MethodHandles.foldArguments(target, filter); + fail(); + } catch (IllegalArgumentException expected) { + } + } + public static void fail() { System.out.println("FAIL"); Thread.dumpStack(); diff --git a/test/Android.bp b/test/Android.bp index 89e409223e..d3244a683a 100644 --- a/test/Android.bp +++ b/test/Android.bp @@ -173,12 +173,13 @@ art_cc_library { whole_static_libs: [ "libart-compiler-gtest", "libart-runtime-gtest", - "libgtest", + "libgtest" ], shared_libs: [ "libartd", "libartd-compiler", "libbase", + "libbacktrace" ], target: { android: { @@ -271,6 +272,8 @@ art_cc_defaults { "929-search/search.cc", "931-agent-thread/agent_thread.cc", "933-misc-events/misc_events.cc", + "936-search-onload/search_onload.cc", + "944-transform-classloaders/classloader.cc", ], shared_libs: [ "libbase", @@ -317,6 +320,7 @@ cc_defaults { "141-class-unload/jni_unload.cc", "148-multithread-gc-annotations/gc_coverage.cc", "149-suspend-all-stress/suspend_all.cc", + "154-gc-loop/heap_interface.cc", "454-get-vreg/get_vreg_jni.cc", "457-regs/regs_jni.cc", "461-get-reference-vreg/get_reference_vreg_jni.cc", diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk index 5bb39fe098..742353da46 100644 --- a/test/Android.run-test.mk +++ b/test/Android.run-test.mk @@ -136,9 +136,9 @@ ifeq ($(ART_TEST_OPTIMIZING_GRAPH_COLOR),true) COMPILER_TYPES += regalloc_gc OPTIMIZING_COMPILER_TYPES += regalloc_gc endif -RELOCATE_TYPES := relocate -ifeq ($(ART_TEST_RUN_TEST_NO_RELOCATE),true) - RELOCATE_TYPES += no-relocate +RELOCATE_TYPES := no-relocate +ifeq ($(ART_TEST_RUN_TEST_RELOCATE),true) + RELOCATE_TYPES += relocate endif ifeq ($(ART_TEST_RUN_TEST_RELOCATE_NO_PATCHOAT),true) RELOCATE_TYPES += relocate-npatchoat @@ -161,7 +161,9 @@ JNI_TYPES := checkjni ifeq ($(ART_TEST_JNI_FORCECOPY),true) JNI_TYPES += forcecopy endif +ifeq ($(ART_TEST_RUN_TEST_IMAGE),true) IMAGE_TYPES := picimage +endif ifeq ($(ART_TEST_RUN_TEST_NO_IMAGE),true) IMAGE_TYPES += no-image endif @@ -379,6 +381,7 @@ TEST_ART_BROKEN_INTERPRETER_ACCESS_CHECK_TESTS := # slows down allocations significantly which these tests do a lot. TEST_ART_BROKEN_GCSTRESS_RUN_TESTS := \ 137-cfi \ + 154-gc-loop \ 908-gc-start-finish \ 913-heaps \ 961-default-iface-resolution-gen \ @@ -436,13 +439,14 @@ TEST_ART_BROKEN_FALLBACK_RUN_TESTS := \ 629-vdex-speed # This test fails without an image. -# 018, 961, 964 often time out. b/34369284 +# 018, 961, 964, 968 often time out. b/34369284 TEST_ART_BROKEN_NO_IMAGE_RUN_TESTS := \ 137-cfi \ 138-duplicate-classes-check \ 018-stack-overflow \ 961-default-iface-resolution-gen \ - 964-default-iface-init + 964-default-iface-init \ + 968-default-partial-compile-gen \ ifneq (,$(filter no-dex2oat,$(PREBUILD_TYPES))) ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),no-dex2oat, \ @@ -604,6 +608,7 @@ TEST_ART_BROKEN_OPTIMIZING_MIPS64_RUN_TESTS := TEST_ART_BROKEN_OPTIMIZING_NONDEBUGGABLE_RUN_TESTS := \ 454-get-vreg \ 457-regs \ + 602-deoptimizeable ifneq (,$(filter $(OPTIMIZING_COMPILER_TYPES),$(COMPILER_TYPES))) ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \ @@ -706,8 +711,10 @@ endif TEST_ART_BROKEN_OPTIMIZING_HEAP_POISONING_RUN_TESTS := -# Tests that check semantics for a non-debuggable app. +# 909: Tests that check semantics for a non-debuggable app. +# 137: relies on AOT code and debuggable makes us JIT always. TEST_ART_BROKEN_DEBUGGABLE_RUN_TESTS := \ + 137-cfi \ 909-attach-agent \ ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \ diff --git a/test/ErroneousInit/ErroneousInit.java b/test/ErroneousInit/ErroneousInit.java new file mode 100644 index 0000000000..67b7b204dc --- /dev/null +++ b/test/ErroneousInit/ErroneousInit.java @@ -0,0 +1,23 @@ +/* + * 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. + */ + +class ErroneousInit { + static { + if (true) { + throw new Error(); + } + } +} diff --git a/test/Nested/Nested.java b/test/Nested/Nested.java index 78b273bec0..f493989268 100644 --- a/test/Nested/Nested.java +++ b/test/Nested/Nested.java @@ -17,4 +17,6 @@ class Nested { class Inner { } + Object x = new Object() { + }; } diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar index 28fa130443..186a1513ee 100755 --- a/test/etc/run-test-jar +++ b/test/etc/run-test-jar @@ -39,7 +39,7 @@ OPTIMIZE="y" PATCHOAT="" PREBUILD="y" QUIET="n" -RELOCATE="y" +RELOCATE="n" STRIP_DEX="n" SECONDARY_DEX="" TIME_OUT="gdb" # "n" (disabled), "timeout" (use timeout), "gdb" (use gdb) @@ -344,7 +344,7 @@ if [ "$IS_JVMTI_TEST" = "y" ]; then else FLAGS="${FLAGS} -agentpath:${agent}=${TEST_NAME},art" FLAGS="${FLAGS} -Xplugin:${plugin}" - FLAGS="${FLAGS} -Xfully-deoptable" + FLAGS="${FLAGS} -Xcompiler-option --debuggable" # Always make the compilation be debuggable. COMPILE_FLAGS="${COMPILE_FLAGS} --debuggable" fi @@ -364,6 +364,8 @@ fi if [ "$HAVE_IMAGE" = "n" ]; then + # Add 5 minutes to give some time to generate the boot image. + TIME_OUT_VALUE=$((${TIME_OUT_VALUE} + 300)) DALVIKVM_BOOT_OPT="-Ximage:/system/non-existant/core.art" else DALVIKVM_BOOT_OPT="-Ximage:${BOOT_IMAGE}" diff --git a/test/run-test b/test/run-test index c78fa35e24..27c700e89e 100755 --- a/test/run-test +++ b/test/run-test @@ -111,7 +111,7 @@ target_mode="yes" dev_mode="no" update_mode="no" debug_mode="no" -relocate="yes" +relocate="no" runtime="art" usage="no" build_only="no" @@ -156,6 +156,7 @@ while true; do shift elif [ "x$1" = "x--jvm" ]; then target_mode="no" + DEX_LOCATION="$tmp_dir" runtime="jvm" image_args="" prebuild_mode="no" @@ -408,7 +409,9 @@ tmp_dir="`cd $oldwd ; python -c "import os; print os.path.realpath('$tmp_dir')"` mkdir -p $tmp_dir # Add thread suspend timeout flag -run_args="${run_args} --runtime-option -XX:ThreadSuspendTimeout=$suspend_timeout" +if [ ! "$runtime" = "jvm" ]; then + run_args="${run_args} --runtime-option -XX:ThreadSuspendTimeout=$suspend_timeout" +fi if [ "$basic_verify" = "true" ]; then # Set HspaceCompactForOOMMinIntervalMs to zero to run hspace compaction for OOM more frequently in tests. @@ -624,8 +627,8 @@ if [ "$usage" = "yes" ]; then echo " --strip-dex Strip the dex files before starting test." echo " --relocate Force the use of relocating in the test, making" echo " the image and oat files be relocated to a random" - echo " address before running. (default)" - echo " --no-relocate Force the use of no relocating in the test" + echo " address before running." + echo " --no-relocate Force the use of no relocating in the test. (default)" echo " --image Run the test using a precompiled boot image. (default)" echo " --no-image Run the test without a precompiled boot image." echo " --host Use the host-mode virtual machine." diff --git a/test/ti-agent/common_helper.cc b/test/ti-agent/common_helper.cc index 80e1797369..ea6359e5e0 100644 --- a/test/ti-agent/common_helper.cc +++ b/test/ti-agent/common_helper.cc @@ -210,6 +210,7 @@ struct CommonTransformationResult { // Map from class name to transformation result. std::map<std::string, std::deque<CommonTransformationResult>> gTransformations; +bool gPopTransformations = true; extern "C" JNIEXPORT void JNICALL Java_Main_addCommonTransformationResult(JNIEnv* env, jclass, @@ -266,7 +267,32 @@ void JNICALL CommonClassFileLoadHookRetransformable(jvmtiEnv* jvmti_env, memcpy(new_data, desired_array.data(), desired_array.size()); *new_class_data = new_data; *new_class_data_len = desired_array.size(); + if (gPopTransformations) { + gTransformations[name_str].pop_front(); + } + } +} + +extern "C" JNIEXPORT void Java_Main_setPopRetransformations(JNIEnv*, + jclass, + jboolean enable) { + gPopTransformations = enable; +} + +extern "C" JNIEXPORT void Java_Main_popTransformationFor(JNIEnv* env, + jclass, + jstring class_name) { + const char* name_chrs = env->GetStringUTFChars(class_name, nullptr); + std::string name_str(name_chrs); + env->ReleaseStringUTFChars(class_name, name_chrs); + if (gTransformations.find(name_str) != gTransformations.end() && + gTransformations[name_str].size() > 0) { gTransformations[name_str].pop_front(); + } else { + std::stringstream err; + err << "No transformations found for class " << name_str; + std::string message = err.str(); + env->ThrowNew(env->FindClass("java/lang/Exception"), message.c_str()); } } @@ -301,11 +327,36 @@ static void DoClassRetransformation(jvmtiEnv* jvmti_env, JNIEnv* env, jobjectArr } } -// TODO Write something useful. extern "C" JNIEXPORT void JNICALL Java_Main_doCommonClassRetransformation(JNIEnv* env, jclass, jobjectArray targets) { - DoClassRetransformation(jvmti_env, env, targets); + jvmtiCapabilities caps; + jvmtiError caps_err = jvmti_env->GetCapabilities(&caps); + if (caps_err != JVMTI_ERROR_NONE) { + env->ThrowNew(env->FindClass("java/lang/Exception"), + "Unable to get current jvmtiEnv capabilities"); + return; + } + + // Allocate a new environment if we don't have the can_retransform_classes capability needed to + // call the RetransformClasses function. + jvmtiEnv* real_env = nullptr; + if (caps.can_retransform_classes != 1) { + JavaVM* vm = nullptr; + if (env->GetJavaVM(&vm) != 0 || + vm->GetEnv(reinterpret_cast<void**>(&real_env), JVMTI_VERSION_1_0) != 0) { + env->ThrowNew(env->FindClass("java/lang/Exception"), + "Unable to create temporary jvmtiEnv for RetransformClasses call."); + return; + } + SetAllCapabilities(real_env); + } else { + real_env = jvmti_env; + } + DoClassRetransformation(real_env, env, targets); + if (caps.can_retransform_classes != 1) { + real_env->DisposeEnvironment(); + } } // Get all capabilities except those related to retransformation. @@ -329,6 +380,38 @@ jint OnLoad(JavaVM* vm, } // namespace common_retransform +namespace common_transform { + +using art::common_retransform::CommonClassFileLoadHookRetransformable; + +// Get all capabilities except those related to retransformation. +jint OnLoad(JavaVM* vm, + char* options ATTRIBUTE_UNUSED, + void* reserved ATTRIBUTE_UNUSED) { + if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0)) { + printf("Unable to get jvmti env!\n"); + return 1; + } + // Don't set the retransform caps + jvmtiCapabilities caps; + jvmti_env->GetPotentialCapabilities(&caps); + caps.can_retransform_classes = 0; + caps.can_retransform_any_class = 0; + jvmti_env->AddCapabilities(&caps); + + // Use the same callback as the retransform test. + jvmtiEventCallbacks cb; + memset(&cb, 0, sizeof(cb)); + cb.ClassFileLoadHook = CommonClassFileLoadHookRetransformable; + if (jvmti_env->SetEventCallbacks(&cb, sizeof(cb)) != JVMTI_ERROR_NONE) { + printf("Unable to set class file load hook cb!\n"); + return 1; + } + return 0; +} + +} // namespace common_transform + static void BindMethod(jvmtiEnv* jenv, JNIEnv* env, jclass klass, @@ -340,15 +423,29 @@ static void BindMethod(jvmtiEnv* jenv, LOG(FATAL) << "Could not get methods"; } - ArtMethod* m = jni::DecodeArtMethod(method); - std::string names[2]; - { + if (IsJVM()) { + // TODO Get the JNI long name + char* klass_name; + jvmtiError klass_result = jenv->GetClassSignature(klass, &klass_name, nullptr); + if (klass_result == JVMTI_ERROR_NONE) { + std::string name_str(name); + std::string klass_str(klass_name); + names[0] = GetJniShortName(klass_str, name_str); + jenv->Deallocate(reinterpret_cast<unsigned char*>(klass_name)); + } else { + LOG(FATAL) << "Could not get class name!"; + } + } else { ScopedObjectAccess soa(Thread::Current()); + ArtMethod* m = jni::DecodeArtMethod(method); names[0] = m->JniShortName(); names[1] = m->JniLongName(); } for (const std::string& mangled_name : names) { + if (mangled_name == "") { + continue; + } void* sym = dlsym(RTLD_DEFAULT, mangled_name.c_str()); if (sym == nullptr) { continue; diff --git a/test/ti-agent/common_helper.h b/test/ti-agent/common_helper.h index c60553dc5a..031850147e 100644 --- a/test/ti-agent/common_helper.h +++ b/test/ti-agent/common_helper.h @@ -27,10 +27,15 @@ namespace common_redefine { jint OnLoad(JavaVM* vm, char* options, void* reserved); } // namespace common_redefine + namespace common_retransform { jint OnLoad(JavaVM* vm, char* options, void* reserved); } // namespace common_retransform +namespace common_transform { +jint OnLoad(JavaVM* vm, char* options, void* reserved); +} // namespace common_transform + extern bool RuntimeIsJVM; diff --git a/test/ti-agent/common_load.cc b/test/ti-agent/common_load.cc index 8ed8e67e42..c5a93568c6 100644 --- a/test/ti-agent/common_load.cc +++ b/test/ti-agent/common_load.cc @@ -28,6 +28,7 @@ #include "901-hello-ti-agent/basics.h" #include "909-attach-agent/attach.h" +#include "936-search-onload/search_onload.h" namespace art { @@ -110,6 +111,17 @@ static AgentLib agents[] = { { "926-multi-obsolescence", common_redefine::OnLoad, nullptr }, { "930-hello-retransform", common_retransform::OnLoad, nullptr }, { "932-transform-saves", common_retransform::OnLoad, nullptr }, + { "934-load-transform", common_retransform::OnLoad, nullptr }, + { "935-non-retransformable", common_transform::OnLoad, nullptr }, + { "936-search-onload", Test936SearchOnload::OnLoad, nullptr }, + { "937-hello-retransform-package", common_retransform::OnLoad, nullptr }, + { "938-load-transform-bcp", common_retransform::OnLoad, nullptr }, + { "939-hello-transformation-bcp", common_redefine::OnLoad, nullptr }, + { "940-recursive-obsolete", common_redefine::OnLoad, nullptr }, + { "941-recursive-obsolete-jit", common_redefine::OnLoad, nullptr }, + { "942-private-recursive", common_redefine::OnLoad, nullptr }, + { "943-private-recursive-jit", common_redefine::OnLoad, nullptr }, + { "944-transform-classloaders", common_redefine::OnLoad, nullptr }, }; static AgentLib* FindAgent(char* name) { |