blob: 15d4dc07bcbcd69bbc7468c38e55483dd8e63e84 [file] [log] [blame]
Nicolas Geoffray78f4fa72015-06-12 09:35:05 +01001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17import java.lang.reflect.Field;
18import java.lang.reflect.Method;
Mathieu Chartierfbc31082016-01-24 11:59:56 -080019import java.util.ArrayList;
Nicolas Geoffray78f4fa72015-06-12 09:35:05 +010020import java.util.List;
21
22class MyClassLoader extends ClassLoader {
23 MyClassLoader() throws Exception {
24 super(MyClassLoader.class.getClassLoader());
25
26 // Some magic to get access to the pathList field of BaseDexClassLoader.
27 ClassLoader loader = getClass().getClassLoader();
28 Class<?> baseDexClassLoader = loader.getClass().getSuperclass();
29 Field f = baseDexClassLoader.getDeclaredField("pathList");
30 f.setAccessible(true);
31 Object pathList = f.get(loader);
32
33 // Some magic to get access to the dexField field of pathList.
Mathieu Chartierfbc31082016-01-24 11:59:56 -080034 // Need to make a copy of the dex elements since we don't want an app image with pre-resolved
35 // things.
Nicolas Geoffray78f4fa72015-06-12 09:35:05 +010036 f = pathList.getClass().getDeclaredField("dexElements");
37 f.setAccessible(true);
Mathieu Chartierfbc31082016-01-24 11:59:56 -080038 Object[] dexElements = (Object[]) f.get(pathList);
39 f = dexElements[0].getClass().getDeclaredField("dexFile");
40 f.setAccessible(true);
41 for (Object element : dexElements) {
42 Object dexFile = f.get(element);
43 // Make copy.
44 Field fileNameField = dexFile.getClass().getDeclaredField("mFileName");
45 fileNameField.setAccessible(true);
46 dexFiles.add(dexFile.getClass().getDeclaredConstructor(String.class).newInstance(
47 fileNameField.get(dexFile)));
48 }
Nicolas Geoffray78f4fa72015-06-12 09:35:05 +010049 }
50
Mathieu Chartierfbc31082016-01-24 11:59:56 -080051 ArrayList<Object> dexFiles = new ArrayList<Object>();
Nicolas Geoffray78f4fa72015-06-12 09:35:05 +010052 Field dexFileField;
53
54 protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException {
Mathieu Chartierfbc31082016-01-24 11:59:56 -080055 // Other classes may also get loaded, ignore those.
56 if (className.equals("LoadedByMyClassLoader") || className.equals("FirstSeenByMyClassLoader")) {
57 System.out.println("Request for " + className);
58 }
Nicolas Geoffray78f4fa72015-06-12 09:35:05 +010059
60 // We're only going to handle LoadedByMyClassLoader.
61 if (className != "LoadedByMyClassLoader") {
62 return getParent().loadClass(className);
63 }
64
65 // Mimic what DexPathList.findClass is doing.
66 try {
Mathieu Chartierfbc31082016-01-24 11:59:56 -080067 for (Object dexFile : dexFiles) {
68 Method method = dexFile.getClass().getDeclaredMethod(
Nicolas Geoffray78f4fa72015-06-12 09:35:05 +010069 "loadClassBinaryName", String.class, ClassLoader.class, List.class);
70
Mathieu Chartierfbc31082016-01-24 11:59:56 -080071 if (dexFile != null) {
Andreas Gampe166aaee2016-07-18 08:27:23 -070072 Class<?> clazz = (Class<?>)method.invoke(dexFile, className, this, null);
Nicolas Geoffray78f4fa72015-06-12 09:35:05 +010073 if (clazz != null) {
74 return clazz;
75 }
76 }
77 }
78 } catch (Exception e) { /* Ignore */ }
79 return null;
80 }
81}
82
83class LoadedByMyClassLoader {
84 /// CHECK-START: void LoadedByMyClassLoader.bar() inliner (before)
85 /// CHECK: LoadClass
86 /// CHECK-NEXT: ClinitCheck
87 /// CHECK-NEXT: InvokeStaticOrDirect
88 /// CHECK-NEXT: LoadClass
89 /// CHECK-NEXT: ClinitCheck
90 /// CHECK-NEXT: StaticFieldGet
91 /// CHECK-NEXT: LoadString
92 /// CHECK-NEXT: NullCheck
93 /// CHECK-NEXT: InvokeVirtual
94
95 /// CHECK-START: void LoadedByMyClassLoader.bar() inliner (after)
96 /// CHECK: LoadClass
97 /// CHECK-NEXT: ClinitCheck
Nicolas Geoffray9714a6e2015-06-23 12:09:55 +010098 /* We inlined FirstSeenByMyClassLoader.$inline$bar */
Nicolas Geoffray78f4fa72015-06-12 09:35:05 +010099 /// CHECK-NEXT: LoadClass
100 /// CHECK-NEXT: ClinitCheck
101 /// CHECK-NEXT: StaticFieldGet
102 /// CHECK-NEXT: LoadString
103 /// CHECK-NEXT: NullCheck
104 /// CHECK-NEXT: InvokeVirtual
105
106 /// CHECK-START: void LoadedByMyClassLoader.bar() register (before)
Nicolas Geoffray9714a6e2015-06-23 12:09:55 +0100107 /* Load and initialize FirstSeenByMyClassLoader */
Nicolas Geoffray78f4fa72015-06-12 09:35:05 +0100108 /// CHECK: LoadClass gen_clinit_check:true
109 /* Load and initialize System */
Alexey Frunze06a46c42016-07-19 15:00:40 -0700110 // There may be MipsComputeBaseMethodAddress here.
111 /// CHECK: LoadClass gen_clinit_check:true
Nicolas Geoffray78f4fa72015-06-12 09:35:05 +0100112 /// CHECK-NEXT: StaticFieldGet
Vladimir Markocac5a7e2016-02-22 10:39:50 +0000113 // There may be HArmDexCacheArraysBase or HX86ComputeBaseMethodAddress here.
114 /// CHECK: LoadString
Nicolas Geoffray78f4fa72015-06-12 09:35:05 +0100115 /// CHECK-NEXT: NullCheck
116 /// CHECK-NEXT: InvokeVirtual
117 public static void bar() {
Nicolas Geoffray9714a6e2015-06-23 12:09:55 +0100118 FirstSeenByMyClassLoader.$inline$bar();
Nicolas Geoffray78f4fa72015-06-12 09:35:05 +0100119 System.out.println("In between the two calls.");
Nicolas Geoffray9714a6e2015-06-23 12:09:55 +0100120 FirstSeenByMyClassLoader.$noinline$bar();
Nicolas Geoffray78f4fa72015-06-12 09:35:05 +0100121 }
122}
123
Nicolas Geoffrayf7714e62015-06-19 10:45:44 +0100124public class Main {
Nicolas Geoffray78f4fa72015-06-12 09:35:05 +0100125 public static void main(String[] args) throws Exception {
126 MyClassLoader o = new MyClassLoader();
Andreas Gampe166aaee2016-07-18 08:27:23 -0700127 Class<?> foo = o.loadClass("LoadedByMyClassLoader");
Nicolas Geoffray78f4fa72015-06-12 09:35:05 +0100128 Method m = foo.getDeclaredMethod("bar");
129 m.invoke(null);
130 }
Nicolas Geoffray78f4fa72015-06-12 09:35:05 +0100131}