diff options
Diffstat (limited to 'test/496-checker-inlining-class-loader/src/Main.java')
-rw-r--r-- | test/496-checker-inlining-class-loader/src/Main.java | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/test/496-checker-inlining-class-loader/src/Main.java b/test/496-checker-inlining-class-loader/src/Main.java new file mode 100644 index 0000000000..15d4dc07bc --- /dev/null +++ b/test/496-checker-inlining-class-loader/src/Main.java @@ -0,0 +1,131 @@ +/* + * 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. + */ + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +class MyClassLoader extends ClassLoader { + MyClassLoader() throws Exception { + super(MyClassLoader.class.getClassLoader()); + + // Some magic to get access to the pathList field of BaseDexClassLoader. + ClassLoader loader = getClass().getClassLoader(); + Class<?> baseDexClassLoader = loader.getClass().getSuperclass(); + Field f = baseDexClassLoader.getDeclaredField("pathList"); + f.setAccessible(true); + Object pathList = f.get(loader); + + // Some magic to get access to the dexField field of pathList. + // Need to make a copy of the dex elements since we don't want an app image with pre-resolved + // things. + f = pathList.getClass().getDeclaredField("dexElements"); + f.setAccessible(true); + Object[] dexElements = (Object[]) f.get(pathList); + f = dexElements[0].getClass().getDeclaredField("dexFile"); + f.setAccessible(true); + for (Object element : dexElements) { + Object dexFile = f.get(element); + // Make copy. + Field fileNameField = dexFile.getClass().getDeclaredField("mFileName"); + fileNameField.setAccessible(true); + dexFiles.add(dexFile.getClass().getDeclaredConstructor(String.class).newInstance( + fileNameField.get(dexFile))); + } + } + + ArrayList<Object> dexFiles = new ArrayList<Object>(); + Field dexFileField; + + protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException { + // Other classes may also get loaded, ignore those. + if (className.equals("LoadedByMyClassLoader") || className.equals("FirstSeenByMyClassLoader")) { + System.out.println("Request for " + className); + } + + // We're only going to handle LoadedByMyClassLoader. + if (className != "LoadedByMyClassLoader") { + return getParent().loadClass(className); + } + + // Mimic what DexPathList.findClass is doing. + try { + for (Object dexFile : dexFiles) { + Method method = dexFile.getClass().getDeclaredMethod( + "loadClassBinaryName", String.class, ClassLoader.class, List.class); + + if (dexFile != null) { + Class<?> clazz = (Class<?>)method.invoke(dexFile, className, this, null); + if (clazz != null) { + return clazz; + } + } + } + } catch (Exception e) { /* Ignore */ } + return null; + } +} + +class LoadedByMyClassLoader { + /// CHECK-START: void LoadedByMyClassLoader.bar() inliner (before) + /// CHECK: LoadClass + /// CHECK-NEXT: ClinitCheck + /// CHECK-NEXT: InvokeStaticOrDirect + /// CHECK-NEXT: LoadClass + /// CHECK-NEXT: ClinitCheck + /// CHECK-NEXT: StaticFieldGet + /// CHECK-NEXT: LoadString + /// CHECK-NEXT: NullCheck + /// CHECK-NEXT: InvokeVirtual + + /// CHECK-START: void LoadedByMyClassLoader.bar() inliner (after) + /// CHECK: LoadClass + /// CHECK-NEXT: ClinitCheck + /* We inlined FirstSeenByMyClassLoader.$inline$bar */ + /// CHECK-NEXT: LoadClass + /// CHECK-NEXT: ClinitCheck + /// CHECK-NEXT: StaticFieldGet + /// CHECK-NEXT: LoadString + /// CHECK-NEXT: NullCheck + /// CHECK-NEXT: InvokeVirtual + + /// CHECK-START: void LoadedByMyClassLoader.bar() register (before) + /* Load and initialize FirstSeenByMyClassLoader */ + /// CHECK: LoadClass gen_clinit_check:true + /* Load and initialize System */ + // There may be MipsComputeBaseMethodAddress here. + /// CHECK: LoadClass gen_clinit_check:true + /// CHECK-NEXT: StaticFieldGet + // There may be HArmDexCacheArraysBase or HX86ComputeBaseMethodAddress here. + /// CHECK: LoadString + /// CHECK-NEXT: NullCheck + /// CHECK-NEXT: InvokeVirtual + public static void bar() { + FirstSeenByMyClassLoader.$inline$bar(); + System.out.println("In between the two calls."); + FirstSeenByMyClassLoader.$noinline$bar(); + } +} + +public class Main { + public static void main(String[] args) throws Exception { + MyClassLoader o = new MyClassLoader(); + Class<?> foo = o.loadClass("LoadedByMyClassLoader"); + Method m = foo.getDeclaredMethod("bar"); + m.invoke(null); + } +} |