diff options
author | 2018-02-01 19:09:59 +0300 | |
---|---|---|
committer | 2018-03-13 17:01:21 +0300 | |
commit | be4c2bd892bd167a50b4dfa7133e70a809197698 (patch) | |
tree | 150898533382fb98c160e265a5f31f66ded754f0 /test/616-cha-unloading/src/Main.java | |
parent | bfce631960ae2ab381180beb55cf34ab3b445aaa (diff) |
Fix dangling SingleImplementations left after class unloading
Test: make test-art-host, manual using sample code
bug: 73143991
Change-Id: I4d56b39c69d4ed60266a8b90b9e9d18fba7b8227
Diffstat (limited to 'test/616-cha-unloading/src/Main.java')
-rw-r--r-- | test/616-cha-unloading/src/Main.java | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/test/616-cha-unloading/src/Main.java b/test/616-cha-unloading/src/Main.java new file mode 100644 index 0000000000..b633a0c22e --- /dev/null +++ b/test/616-cha-unloading/src/Main.java @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2018 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; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; + +public class Main { + static final String DEX_FILE = System.getenv("DEX_LOCATION") + "/616-cha-unloading-ex.jar"; + static final String LIBRARY_SEARCH_PATH = System.getProperty("java.library.path"); + static Constructor<? extends ClassLoader> sConstructor; + + private static class CHAUnloaderRetType { + private CHAUnloaderRetType(WeakReference<ClassLoader> cl, + AbstractCHATester obj, + long methodPtr) { + this.cl = cl; + this.obj = obj; + this.methodPtr = methodPtr; + } + public WeakReference<ClassLoader> cl; + public AbstractCHATester obj; + public long methodPtr; + } + + public static void main(String[] args) throws Exception { + System.loadLibrary(args[0]); + + Class<ClassLoader> pathClassLoader = (Class<ClassLoader>) Class.forName("dalvik.system.PathClassLoader"); + sConstructor = + pathClassLoader.getDeclaredConstructor(String.class, String.class, ClassLoader.class); + + testUnload(); + } + + private static void testUnload() throws Exception { + // Load a concrete class, then unload it. Get a deleted ArtMethod to test if it'll be inlined. + CHAUnloaderRetType result = doUnloadLoader(); + WeakReference<ClassLoader> loader = result.cl; + long methodPtr = result.methodPtr; + // Check that the classloader is indeed unloaded. + System.out.println(loader.get()); + + // Reuse the linear alloc so old pointers so it becomes invalid. + boolean ret = tryReuseArenaOfMethod(methodPtr, 10); + // Check that we indeed reused it. + System.out.println(ret); + + // Try to JIT-compile under dangerous conditions. + ensureJitCompiled(Main.class, "targetMethodForJit"); + System.out.println("Done"); + } + + private static void doUnloading() { + // Do multiple GCs to prevent rare flakiness if some other thread is keeping the + // classloader live. + for (int i = 0; i < 5; ++i) { + Runtime.getRuntime().gc(); + } + } + + private static CHAUnloaderRetType setupLoader() + throws Exception { + ClassLoader loader = sConstructor.newInstance( + DEX_FILE, LIBRARY_SEARCH_PATH, ClassLoader.getSystemClassLoader()); + Class<?> concreteCHATester = loader.loadClass("ConcreteCHATester"); + + // Preemptively compile methods to prevent delayed JIT tasks from blocking the unloading. + ensureJitCompiled(concreteCHATester, "<init>"); + ensureJitCompiled(concreteCHATester, "lonelyMethod"); + + Object obj = concreteCHATester.newInstance(); + Method lonelyMethod = concreteCHATester.getDeclaredMethod("lonelyMethod"); + + // Get a pointer to a region that shall be not used after the unloading. + long artMethod = getArtMethod(lonelyMethod); + + AbstractCHATester ret = null; + return new CHAUnloaderRetType(new WeakReference(loader), ret, artMethod); + } + + private static CHAUnloaderRetType targetMethodForJit(int mode) + throws Exception { + CHAUnloaderRetType ret = new CHAUnloaderRetType(null, null, 0); + if (mode == 0) { + ret = setupLoader(); + } else if (mode == 1) { + // This branch is not supposed to be executed. It shall trigger "lonelyMethod" inlining + // during jit compilation of "targetMethodForJit". + ret = setupLoader(); + AbstractCHATester obj = ret.obj; + obj.lonelyMethod(); + } + return ret; + } + + private static CHAUnloaderRetType doUnloadLoader() + throws Exception { + CHAUnloaderRetType result = targetMethodForJit(0); + doUnloading(); + return result; + } + + private static native void ensureJitCompiled(Class<?> itf, String method_name); + private static native long getArtMethod(Object javaMethod); + private static native boolean tryReuseArenaOfMethod(long artMethod, int tries_count); +} |