1579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson/*
2579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Copyright (C) 2011 The Android Open Source Project
3579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
4579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Licensed under the Apache License, Version 2.0 (the "License");
5579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * you may not use this file except in compliance with the License.
6579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * You may obtain a copy of the License at
7579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
8579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *      http://www.apache.org/licenses/LICENSE-2.0
9579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
10579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Unless required by applicable law or agreed to in writing, software
11579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS,
12579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * See the License for the specific language governing permissions and
14579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * limitations under the License.
15579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */
16579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
17b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffinpackage com.android.dx;
18579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
19b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffinimport com.android.dex.DexFormat;
20579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.dex.DexOptions;
21579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.dex.code.DalvCode;
22579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.dex.code.PositionList;
23579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.dex.code.RopTranslator;
24579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.dex.file.ClassDefItem;
25579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.dex.file.DexFile;
26579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.dex.file.EncodedField;
27579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.dex.file.EncodedMethod;
285624228626d7cdf206de25a6981ba8107be61057Jesse Wilsonimport com.android.dx.rop.code.AccessFlags;
29579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.code.LocalVariableInfo;
30579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.code.RopMethod;
31579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.cst.CstString;
32579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.cst.CstType;
33579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.type.StdTypeList;
34171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann
35579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.io.File;
36579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.io.FileOutputStream;
37579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.io.IOException;
38579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.lang.reflect.InvocationTargetException;
3923abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilsonimport java.lang.reflect.Modifier;
40054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousefimport java.util.Arrays;
41054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousefimport java.util.Iterator;
42579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.util.LinkedHashMap;
43579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.util.Map;
44054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousefimport java.util.Set;
45579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.util.jar.JarEntry;
46579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.util.jar.JarOutputStream;
47579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
48b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffinimport static com.android.dx.rop.code.AccessFlags.ACC_CONSTRUCTOR;
49b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffinimport static java.lang.reflect.Modifier.PRIVATE;
50b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffinimport static java.lang.reflect.Modifier.STATIC;
51b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin
52314cb2efb7b1d8d9b584a6e0bd82727168cfd181Philip P. Moltmannimport android.util.Log;
53314cb2efb7b1d8d9b584a6e0bd82727168cfd181Philip P. Moltmann
54579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson/**
55b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin * Generates a <strong>D</strong>alvik <strong>EX</strong>ecutable (dex)
56b0f6ea8cec29bd1b2453e8fd15d9c6f65ca3ea2cJesse Wilson * file for execution on Android. Dex files define classes and interfaces,
570e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson * including their member methods and fields, executable code, and debugging
580e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson * information. They also define annotations, though this API currently has no
590e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson * facility to create a dex file that contains annotations.
600e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *
610e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson * <p>This library is intended to satisfy two use cases:
620e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson * <ul>
630e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *   <li><strong>For runtime code generation.</strong> By embedding this library
640e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *       in your Android application, you can dynamically generate and load
650e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *       executable code. This approach takes advantage of the fact that the
660e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *       host environment and target environment are both Android.
670e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *   <li><strong>For compile time code generation.</strong> You may use this
680e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *       library as a part of a compiler that targets Android. In this scenario
690e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *       the generated dex file must be installed on an Android device before it
700e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *       can be executed.
710e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson * </ul>
720e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *
730e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson * <h3>Example: Fibonacci</h3>
740e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson * To illustrate how this API is used, we'll use DexMaker to generate a class
75008290ab55ac24ef656d254e41a03ad2b1fba7d2Jesse Wilson * equivalent to the following Java source: <pre> {@code
760e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *
770e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson * package com.publicobject.fib;
780e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *
790e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson * public class Fibonacci {
800e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *   public static int fib(int i) {
810e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *     if (i < 2) {
820e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *       return i;
830e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *     }
840e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *     return fib(i - 1) + fib(i - 2);
850e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *   }
860e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson * }}</pre>
870e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *
880e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson * <p>We start by creating a {@link TypeId} to identify the generated {@code
890e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson * Fibonacci} class. DexMaker identifies types by their internal names like
900e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson * {@code Ljava/lang/Object;} rather than their Java identifiers like {@code
910e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson * java.lang.Object}. <pre>   {@code
920e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *
930e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *   TypeId<?> fibonacci = TypeId.get("Lcom/google/dexmaker/examples/Fibonacci;");
940e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson * }</pre>
950e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *
960e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson * <p>Next we declare the class. It allows us to specify the type's source file
970e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson * for stack traces, its modifiers, its superclass, and the interfaces it
980e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson * implements. In this case, {@code Fibonacci} is a public class that extends
990e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson * from {@code Object}: <pre>   {@code
1000e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *
1010e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *   String fileName = "Fibonacci.generated";
1020e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *   DexMaker dexMaker = new DexMaker();
1030e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *   dexMaker.declare(fibonacci, fileName, Modifier.PUBLIC, TypeId.OBJECT);
1040e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson * }</pre>
1050e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson * It is illegal to declare members of a class without also declaring the class
1060e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson * itself.
1070e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *
1080e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson * <p>To make it easier to go from our Java method to dex instructions, we'll
1090e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson * manually translate it to pseudocode fit for an assembler. We need to replace
1100e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson * control flow like {@code if()} blocks and {@code for()} loops with labels and
1110e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson * branches. We'll also avoid performing multiple operations in one statement,
1120e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson * using local variables to hold intermediate values as necessary:
1130e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson * <pre>   {@code
1140e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *
1150e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *   int constant1 = 1;
1160e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *   int constant2 = 2;
1170e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *   if (i < constant2) goto baseCase;
1180e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *   int a = i - constant1;
1190e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *   int b = i - constant2;
1200e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *   int c = fib(a);
1210e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *   int d = fib(b);
1220e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *   int result = c + d;
1230e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *   return result;
1240e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson * baseCase:
1250e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *   return i;
1260e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson * }</pre>
1270e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *
128008290ab55ac24ef656d254e41a03ad2b1fba7d2Jesse Wilson * <p>We look up the {@code MethodId} for the method on the declaring type. This
129008290ab55ac24ef656d254e41a03ad2b1fba7d2Jesse Wilson * takes the method's return type (possibly {@link TypeId#VOID}), its name and
130008290ab55ac24ef656d254e41a03ad2b1fba7d2Jesse Wilson * its parameters types. Next we declare the method, specifying its modifiers by
131008290ab55ac24ef656d254e41a03ad2b1fba7d2Jesse Wilson * bitwise ORing constants from {@link java.lang.reflect.Modifier}. The declare
132008290ab55ac24ef656d254e41a03ad2b1fba7d2Jesse Wilson * call returns a {@link Code} object, which we'll use to define the method's
133008290ab55ac24ef656d254e41a03ad2b1fba7d2Jesse Wilson * instructions. <pre>   {@code
1340e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *
1350e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *   MethodId<?, Integer> fib = fibonacci.getMethod(TypeId.INT, "fib", TypeId.INT);
1360e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *   Code code = dexMaker.declare(fib, Modifier.PUBLIC | Modifier.STATIC);
1370e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson * }</pre>
1380e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *
1390e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson * <p>One limitation of {@code DexMaker}'s API is that it requires all local
1400e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson * variables to be created before any instructions are emitted. Use {@link
141008290ab55ac24ef656d254e41a03ad2b1fba7d2Jesse Wilson * Code#newLocal newLocal()} to create a new local variable. The method's
142008290ab55ac24ef656d254e41a03ad2b1fba7d2Jesse Wilson * parameters are exposed as locals using {@link Code#getParameter
143008290ab55ac24ef656d254e41a03ad2b1fba7d2Jesse Wilson * getParameter()}. For non-static methods the {@code this} pointer is exposed
144008290ab55ac24ef656d254e41a03ad2b1fba7d2Jesse Wilson * using {@link Code#getThis getThis()}. Here we declare all of the local
145008290ab55ac24ef656d254e41a03ad2b1fba7d2Jesse Wilson * variables that we'll need for our {@code fib()} method: <pre>   {@code
1460e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *
1470e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *   Local<Integer> i = code.getParameter(0, TypeId.INT);
1480e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *   Local<Integer> constant1 = code.newLocal(TypeId.INT);
1490e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *   Local<Integer> constant2 = code.newLocal(TypeId.INT);
1500e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *   Local<Integer> a = code.newLocal(TypeId.INT);
1510e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *   Local<Integer> b = code.newLocal(TypeId.INT);
1520e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *   Local<Integer> c = code.newLocal(TypeId.INT);
1530e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *   Local<Integer> d = code.newLocal(TypeId.INT);
1540e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *   Local<Integer> result = code.newLocal(TypeId.INT);
1550e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson * }</pre>
1560e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *
157008290ab55ac24ef656d254e41a03ad2b1fba7d2Jesse Wilson * <p>Notice that {@link Local} has a type parameter of {@code Integer}. This is
158008290ab55ac24ef656d254e41a03ad2b1fba7d2Jesse Wilson * useful for generating code that works with existing types like {@code String}
159008290ab55ac24ef656d254e41a03ad2b1fba7d2Jesse Wilson * and {@code Integer}, but it can be a hindrance when generating code that
160008290ab55ac24ef656d254e41a03ad2b1fba7d2Jesse Wilson * involves new types. For this reason you may prefer to use raw types only and
161008290ab55ac24ef656d254e41a03ad2b1fba7d2Jesse Wilson * add {@code @SuppressWarnings("unsafe")} on your calling code. This will yield
162008290ab55ac24ef656d254e41a03ad2b1fba7d2Jesse Wilson * the same result but you won't get IDE support if you make a type error.
1630e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *
164b0f6ea8cec29bd1b2453e8fd15d9c6f65ca3ea2cJesse Wilson * <p>We're ready to start defining our method's instructions. The {@link Code}
165b0f6ea8cec29bd1b2453e8fd15d9c6f65ca3ea2cJesse Wilson * class catalogs the available instructions and their use. <pre>   {@code
1660e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *
1670e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *   code.loadConstant(constant1, 1);
1680e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *   code.loadConstant(constant2, 2);
16923abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson *   Label baseCase = new Label();
1700e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *   code.compare(Comparison.LT, baseCase, i, constant2);
1710e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *   code.op(BinaryOp.SUBTRACT, a, i, constant1);
1720e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *   code.op(BinaryOp.SUBTRACT, b, i, constant2);
1730e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *   code.invokeStatic(fib, c, a);
1740e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *   code.invokeStatic(fib, d, b);
1750e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *   code.op(BinaryOp.ADD, result, c, d);
1760e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *   code.returnValue(result);
1770e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *   code.mark(baseCase);
1780e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *   code.returnValue(i);
1790e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson * }</pre>
1800e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *
181008290ab55ac24ef656d254e41a03ad2b1fba7d2Jesse Wilson * <p>We're done defining the dex file. We just need to write it to the
182008290ab55ac24ef656d254e41a03ad2b1fba7d2Jesse Wilson * filesystem or load it into the current process. For this example we'll load
1830e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson * the generated code into the current process. This only works when the current
1843e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * process is running on Android. We use {@link #generateAndLoad
1853e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * generateAndLoad()} which takes the class loader that will be used as our
1863e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * generated code's parent class loader. It also requires a directory where
1873e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * temporary files can be written. <pre>   {@code
1880e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *
1890e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *   ClassLoader loader = dexMaker.generateAndLoad(
1905692b3b0303c55524ff206dc7840ffdb1fa47628Jesse Wilson *       FibonacciMaker.class.getClassLoader(), getDataDirectory());
1910e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson * }</pre>
1920e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson * Finally we'll use reflection to lookup our generated class on its class
1930e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson * loader and invoke its {@code fib()} method: <pre>   {@code
1940e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *
1950e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *   Class<?> fibonacciClass = loader.loadClass("com.google.dexmaker.examples.Fibonacci");
1960e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *   Method fibMethod = fibonacciClass.getMethod("fib", int.class);
1970e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson *   System.out.println(fibMethod.invoke(null, 8));
1980e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson * }</pre>
199579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */
200ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilsonpublic final class DexMaker {
201314cb2efb7b1d8d9b584a6e0bd82727168cfd181Philip P. Moltmann    private static final String LOG_TAG = DexMaker.class.getSimpleName();
202314cb2efb7b1d8d9b584a6e0bd82727168cfd181Philip P. Moltmann
203b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin    private final Map<TypeId<?>, TypeDeclaration> types = new LinkedHashMap<>();
204171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann    private ClassLoader sharedClassLoader;
205d4a20568bcbaa34526676e4758e011ea32784825Philip P. Moltmann    private DexFile outputDex;
206314cb2efb7b1d8d9b584a6e0bd82727168cfd181Philip P. Moltmann    private boolean markAsTrusted;
207579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
2083e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson    /**
2093e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * Creates a new {@code DexMaker} instance, which can be used to create a
2103e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * single dex file.
2113e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     */
2123e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson    public DexMaker() {
2133e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson    }
2143e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson
215d4a20568bcbaa34526676e4758e011ea32784825Philip P. Moltmann    TypeDeclaration getTypeDeclaration(TypeId<?> type) {
216579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        TypeDeclaration result = types.get(type);
217579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (result == null) {
218579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            result = new TypeDeclaration(type);
219579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            types.put(type, result);
220579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
221579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return result;
222579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
223579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
224579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
22523abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson     * Declares {@code type}.
22623abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson     *
22723abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson     * @param flags a bitwise combination of {@link Modifier#PUBLIC}, {@link
22823abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson     *     Modifier#FINAL} and {@link Modifier#ABSTRACT}.
229579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
2300e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson    public void declare(TypeId<?> type, String sourceFile, int flags,
2310e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson            TypeId<?> supertype, TypeId<?>... interfaces) {
232579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        TypeDeclaration declaration = getTypeDeclaration(type);
233c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson        int supportedFlags = Modifier.PUBLIC | Modifier.FINAL | Modifier.ABSTRACT;
234c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson        if ((flags & ~supportedFlags) != 0) {
235c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson            throw new IllegalArgumentException("Unexpected flag: "
236c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson                    + Integer.toHexString(flags));
237c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson        }
238579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (declaration.declared) {
239579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new IllegalStateException("already declared: " + type);
240579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
241579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        declaration.declared = true;
242579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        declaration.flags = flags;
243579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        declaration.supertype = supertype;
244579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        declaration.sourceFile = sourceFile;
245579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        declaration.interfaces = new TypeList(interfaces);
246579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
247579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
248579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
249c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson     * Declares a method or constructor.
25023abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson     *
25123abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson     * @param flags a bitwise combination of {@link Modifier#PUBLIC}, {@link
25223abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson     *     Modifier#PRIVATE}, {@link Modifier#PROTECTED}, {@link Modifier#STATIC},
253c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson     *     {@link Modifier#FINAL} and {@link Modifier#SYNCHRONIZED}.
2545624228626d7cdf206de25a6981ba8107be61057Jesse Wilson     *     <p><strong>Warning:</strong> the {@link Modifier#SYNCHRONIZED} flag
2555624228626d7cdf206de25a6981ba8107be61057Jesse Wilson     *     is insufficient to generate a synchronized method. You must also use
2565624228626d7cdf206de25a6981ba8107be61057Jesse Wilson     *     {@link Code#monitorEnter} and {@link Code#monitorExit} to acquire
2575624228626d7cdf206de25a6981ba8107be61057Jesse Wilson     *     a monitor.
25890699b97998f1582a921202fb909f17f9718d177Jesse Wilson     */
259579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public Code declare(MethodId<?, ?> method, int flags) {
260579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        TypeDeclaration typeDeclaration = getTypeDeclaration(method.declaringType);
261579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (typeDeclaration.methods.containsKey(method)) {
262579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new IllegalStateException("already declared: " + method);
263579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
264c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson
265c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson        int supportedFlags = Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED
266c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson                | Modifier.STATIC | Modifier.FINAL | Modifier.SYNCHRONIZED;
267c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson        if ((flags & ~supportedFlags) != 0) {
268c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson            throw new IllegalArgumentException("Unexpected flag: "
269c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson                    + Integer.toHexString(flags));
270c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson        }
271c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson
2725624228626d7cdf206de25a6981ba8107be61057Jesse Wilson        // replace the SYNCHRONIZED flag with the DECLARED_SYNCHRONIZED flag
2735624228626d7cdf206de25a6981ba8107be61057Jesse Wilson        if ((flags & Modifier.SYNCHRONIZED) != 0) {
2745624228626d7cdf206de25a6981ba8107be61057Jesse Wilson            flags = (flags & ~Modifier.SYNCHRONIZED) | AccessFlags.ACC_DECLARED_SYNCHRONIZED;
2755624228626d7cdf206de25a6981ba8107be61057Jesse Wilson        }
276c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson
277171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann        if (method.isConstructor() || method.isStaticInitializer()) {
278c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson            flags |= ACC_CONSTRUCTOR;
279c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson        }
280c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson
281579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        MethodDeclaration methodDeclaration = new MethodDeclaration(method, flags);
282579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        typeDeclaration.methods.put(method, methodDeclaration);
283579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return methodDeclaration.code;
284579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
285579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
286579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
28723abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson     * Declares a field.
28823abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson     *
28923abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson     * @param flags a bitwise combination of {@link Modifier#PUBLIC}, {@link
29023abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson     *     Modifier#PRIVATE}, {@link Modifier#PROTECTED}, {@link Modifier#STATIC},
29123abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson     *     {@link Modifier#FINAL}, {@link Modifier#VOLATILE}, and {@link
29223abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson     *     Modifier#TRANSIENT}.
293c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson     * @param staticValue a constant representing the initial value for the
294c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson     *     static field, possibly null. This must be null if this field is
295c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson     *     non-static.
296579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
297579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void declare(FieldId<?, ?> fieldId, int flags, Object staticValue) {
298579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        TypeDeclaration typeDeclaration = getTypeDeclaration(fieldId.declaringType);
299579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (typeDeclaration.fields.containsKey(fieldId)) {
300579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new IllegalStateException("already declared: " + fieldId);
301579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
302c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson
303c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson        int supportedFlags = Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED
304c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson                | Modifier.STATIC | Modifier.FINAL | Modifier.VOLATILE | Modifier.TRANSIENT;
305c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson        if ((flags & ~supportedFlags) != 0) {
306c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson            throw new IllegalArgumentException("Unexpected flag: "
307c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson                    + Integer.toHexString(flags));
308c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson        }
309c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson
310c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson        if ((flags & Modifier.STATIC) == 0 && staticValue != null) {
311c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson            throw new IllegalArgumentException("staticValue is non-null, but field is not static");
312c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson        }
313c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson
314579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        FieldDeclaration fieldDeclaration = new FieldDeclaration(fieldId, flags, staticValue);
315579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        typeDeclaration.fields.put(fieldId, fieldDeclaration);
316579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
317579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
318579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
31923abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson     * Generates a dex file and returns its bytes.
320579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
321579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public byte[] generate() {
322d4a20568bcbaa34526676e4758e011ea32784825Philip P. Moltmann        if (outputDex == null) {
323d4a20568bcbaa34526676e4758e011ea32784825Philip P. Moltmann            DexOptions options = new DexOptions();
324d4a20568bcbaa34526676e4758e011ea32784825Philip P. Moltmann            options.targetApiLevel = DexFormat.API_NO_EXTENDED_OPCODES;
325d4a20568bcbaa34526676e4758e011ea32784825Philip P. Moltmann            outputDex = new DexFile(options);
326d4a20568bcbaa34526676e4758e011ea32784825Philip P. Moltmann        }
327579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
328579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (TypeDeclaration typeDeclaration : types.values()) {
329579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            outputDex.add(typeDeclaration.toClassDefItem());
330579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
331579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
332579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        try {
333579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return outputDex.toDex(null, false);
334579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (IOException e) {
335579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new RuntimeException(e);
336579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
337579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
338579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
339054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    // Generate a file name for the jar by taking a checksum of MethodIds and
340054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    // parent class types.
341054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    private String generateFileName() {
342054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        int checksum = 1;
343054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
344054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        Set<TypeId<?>> typesKeySet = types.keySet();
345054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        Iterator<TypeId<?>> it = typesKeySet.iterator();
346054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        int[] checksums = new int[typesKeySet.size()];
347054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        int i = 0;
348054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
349054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        while (it.hasNext()) {
350054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            TypeId<?> typeId = it.next();
351054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            TypeDeclaration decl = getTypeDeclaration(typeId);
352054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            Set<MethodId> methodSet = decl.methods.keySet();
353054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            if (decl.supertype != null) {
354054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef                checksums[i++] = 31 * decl.supertype.hashCode() + methodSet.hashCode();
355054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            }
356054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        }
357054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        Arrays.sort(checksums);
358054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
359054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        for (int sum : checksums) {
360054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            checksum *= 31;
361054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            checksum += sum;
362054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        }
363054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
364054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        return "Generated_" + checksum +".jar";
365054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
366054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
367314cb2efb7b1d8d9b584a6e0bd82727168cfd181Philip P. Moltmann    /**
368314cb2efb7b1d8d9b584a6e0bd82727168cfd181Philip P. Moltmann     * Set shared class loader to use.
369314cb2efb7b1d8d9b584a6e0bd82727168cfd181Philip P. Moltmann     *
370314cb2efb7b1d8d9b584a6e0bd82727168cfd181Philip P. Moltmann     * <p>If a class wants to call package private methods of another class they need to share a
371314cb2efb7b1d8d9b584a6e0bd82727168cfd181Philip P. Moltmann     * class loader. One common case for this requirement is a mock class wanting to mock package
372314cb2efb7b1d8d9b584a6e0bd82727168cfd181Philip P. Moltmann     * private methods of the original class.
373314cb2efb7b1d8d9b584a6e0bd82727168cfd181Philip P. Moltmann     *
374314cb2efb7b1d8d9b584a6e0bd82727168cfd181Philip P. Moltmann     * @param classLoader the class loader the new class should be loaded by
375314cb2efb7b1d8d9b584a6e0bd82727168cfd181Philip P. Moltmann     */
376171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann    public void setSharedClassLoader(ClassLoader classLoader) {
377171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann        this.sharedClassLoader = classLoader;
378171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann    }
379171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann
380314cb2efb7b1d8d9b584a6e0bd82727168cfd181Philip P. Moltmann    public void markAsTrusted() {
381314cb2efb7b1d8d9b584a6e0bd82727168cfd181Philip P. Moltmann        this.markAsTrusted = true;
382314cb2efb7b1d8d9b584a6e0bd82727168cfd181Philip P. Moltmann    }
383314cb2efb7b1d8d9b584a6e0bd82727168cfd181Philip P. Moltmann
384171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann    private ClassLoader generateClassLoader(File result, File dexCache, ClassLoader parent) {
385054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        try {
386314cb2efb7b1d8d9b584a6e0bd82727168cfd181Philip P. Moltmann            // Try to load the class so that it can call hidden APIs. This is required for spying
387314cb2efb7b1d8d9b584a6e0bd82727168cfd181Philip P. Moltmann            // on system classes as real-methods of these classes might call blacklisted APIs
388314cb2efb7b1d8d9b584a6e0bd82727168cfd181Philip P. Moltmann            if (markAsTrusted) {
389314cb2efb7b1d8d9b584a6e0bd82727168cfd181Philip P. Moltmann                try {
390314cb2efb7b1d8d9b584a6e0bd82727168cfd181Philip P. Moltmann                    if (sharedClassLoader != null) {
391314cb2efb7b1d8d9b584a6e0bd82727168cfd181Philip P. Moltmann                        ClassLoader loader = parent != null ? parent : sharedClassLoader;
392314cb2efb7b1d8d9b584a6e0bd82727168cfd181Philip P. Moltmann                        loader.getClass().getMethod("addDexPath", String.class,
393314cb2efb7b1d8d9b584a6e0bd82727168cfd181Philip P. Moltmann                                Boolean.TYPE).invoke(loader, result.getPath(), true);
394314cb2efb7b1d8d9b584a6e0bd82727168cfd181Philip P. Moltmann                        return loader;
395314cb2efb7b1d8d9b584a6e0bd82727168cfd181Philip P. Moltmann                    } else {
396314cb2efb7b1d8d9b584a6e0bd82727168cfd181Philip P. Moltmann                        return (ClassLoader) Class.forName("dalvik.system.BaseDexClassLoader")
397314cb2efb7b1d8d9b584a6e0bd82727168cfd181Philip P. Moltmann                                .getConstructor(String.class, File.class, String.class,
398314cb2efb7b1d8d9b584a6e0bd82727168cfd181Philip P. Moltmann                                        ClassLoader.class, Boolean.TYPE)
399314cb2efb7b1d8d9b584a6e0bd82727168cfd181Philip P. Moltmann                                .newInstance(result.getPath(), dexCache.getAbsoluteFile(), null,
400314cb2efb7b1d8d9b584a6e0bd82727168cfd181Philip P. Moltmann                                        parent, true);
401314cb2efb7b1d8d9b584a6e0bd82727168cfd181Philip P. Moltmann                    }
402314cb2efb7b1d8d9b584a6e0bd82727168cfd181Philip P. Moltmann                } catch (InvocationTargetException e) {
403314cb2efb7b1d8d9b584a6e0bd82727168cfd181Philip P. Moltmann                    if (e.getCause() instanceof SecurityException) {
404314cb2efb7b1d8d9b584a6e0bd82727168cfd181Philip P. Moltmann                        Log.i(LOG_TAG, "Cannot allow to call blacklisted super methods. This might "
405314cb2efb7b1d8d9b584a6e0bd82727168cfd181Philip P. Moltmann                                + "break spying on system classes.", e.getCause());
406314cb2efb7b1d8d9b584a6e0bd82727168cfd181Philip P. Moltmann                    } else {
407314cb2efb7b1d8d9b584a6e0bd82727168cfd181Philip P. Moltmann                        throw e;
408314cb2efb7b1d8d9b584a6e0bd82727168cfd181Philip P. Moltmann                    }
409314cb2efb7b1d8d9b584a6e0bd82727168cfd181Philip P. Moltmann                }
410314cb2efb7b1d8d9b584a6e0bd82727168cfd181Philip P. Moltmann            }
411314cb2efb7b1d8d9b584a6e0bd82727168cfd181Philip P. Moltmann
412171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann            if (sharedClassLoader != null) {
413171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann                ClassLoader loader = parent != null ? parent : sharedClassLoader;
414db20bbcc82de39f499a804d215851995041f3bcfPaul Duffin                loader.getClass().getMethod("addDexPath", String.class).invoke(loader,
415171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann                        result.getPath());
416db20bbcc82de39f499a804d215851995041f3bcfPaul Duffin                return loader;
417db20bbcc82de39f499a804d215851995041f3bcfPaul Duffin            } else {
418db20bbcc82de39f499a804d215851995041f3bcfPaul Duffin                return (ClassLoader) Class.forName("dalvik.system.DexClassLoader")
419db20bbcc82de39f499a804d215851995041f3bcfPaul Duffin                        .getConstructor(String.class, String.class, String.class, ClassLoader.class)
420db20bbcc82de39f499a804d215851995041f3bcfPaul Duffin                        .newInstance(result.getPath(), dexCache.getAbsolutePath(), null, parent);
421db20bbcc82de39f499a804d215851995041f3bcfPaul Duffin            }
422054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        } catch (ClassNotFoundException e) {
423054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            throw new UnsupportedOperationException("load() requires a Dalvik VM", e);
424054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        } catch (InvocationTargetException e) {
425054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            throw new RuntimeException(e.getCause());
426054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        } catch (InstantiationException e) {
427054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            throw new AssertionError();
428054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        } catch (NoSuchMethodException e) {
429054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            throw new AssertionError();
430054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        } catch (IllegalAccessException e) {
431054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            throw new AssertionError();
432054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        }
433054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
434054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
435579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
43623abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson     * Generates a dex file and loads its types into the current process.
437579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
43873cfa4498f640e0915b95fc806db4a0d54172fe8Jesse Wilson     * <h3>Picking a dex cache directory</h3>
43973cfa4498f640e0915b95fc806db4a0d54172fe8Jesse Wilson     * The {@code dexCache} should be an application-private directory. If
44073cfa4498f640e0915b95fc806db4a0d54172fe8Jesse Wilson     * you pass a world-writable directory like {@code /sdcard} a malicious app
44173cfa4498f640e0915b95fc806db4a0d54172fe8Jesse Wilson     * could inject code into your process. Most applications should use this:
44273cfa4498f640e0915b95fc806db4a0d54172fe8Jesse Wilson     * <pre>   {@code
443579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
44473cfa4498f640e0915b95fc806db4a0d54172fe8Jesse Wilson     *     File dexCache = getApplicationContext().getDir("dx", Context.MODE_PRIVATE);
44573cfa4498f640e0915b95fc806db4a0d54172fe8Jesse Wilson     * }</pre>
44673cfa4498f640e0915b95fc806db4a0d54172fe8Jesse Wilson     * If the {@code dexCache} is null, this method will consult the {@code
44773cfa4498f640e0915b95fc806db4a0d54172fe8Jesse Wilson     * dexmaker.dexcache} system property. If that exists, it will be used for
44873cfa4498f640e0915b95fc806db4a0d54172fe8Jesse Wilson     * the dex cache. If it doesn't exist, this method will attempt to guess
44973cfa4498f640e0915b95fc806db4a0d54172fe8Jesse Wilson     * the application's private data directory as a last resort. If that fails,
45073cfa4498f640e0915b95fc806db4a0d54172fe8Jesse Wilson     * this method will fail with an unchecked exception. You can avoid the
45173cfa4498f640e0915b95fc806db4a0d54172fe8Jesse Wilson     * exception by either providing a non-null value or setting the system
45273cfa4498f640e0915b95fc806db4a0d54172fe8Jesse Wilson     * property.
453579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
45473cfa4498f640e0915b95fc806db4a0d54172fe8Jesse Wilson     * @param parent the parent ClassLoader to be used when loading our
45573cfa4498f640e0915b95fc806db4a0d54172fe8Jesse Wilson     *     generated types
45673cfa4498f640e0915b95fc806db4a0d54172fe8Jesse Wilson     * @param dexCache the destination directory where generated and optimized
45773cfa4498f640e0915b95fc806db4a0d54172fe8Jesse Wilson     *     dex files will be written. If null, this class will try to guess the
45873cfa4498f640e0915b95fc806db4a0d54172fe8Jesse Wilson     *     application's private data dir.
459579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
46073cfa4498f640e0915b95fc806db4a0d54172fe8Jesse Wilson    public ClassLoader generateAndLoad(ClassLoader parent, File dexCache) throws IOException {
46173cfa4498f640e0915b95fc806db4a0d54172fe8Jesse Wilson        if (dexCache == null) {
46273cfa4498f640e0915b95fc806db4a0d54172fe8Jesse Wilson            String property = System.getProperty("dexmaker.dexcache");
46373cfa4498f640e0915b95fc806db4a0d54172fe8Jesse Wilson            if (property != null) {
46473cfa4498f640e0915b95fc806db4a0d54172fe8Jesse Wilson                dexCache = new File(property);
46573cfa4498f640e0915b95fc806db4a0d54172fe8Jesse Wilson            } else {
46673cfa4498f640e0915b95fc806db4a0d54172fe8Jesse Wilson                dexCache = new AppDataDirGuesser().guess();
46773cfa4498f640e0915b95fc806db4a0d54172fe8Jesse Wilson                if (dexCache == null) {
46873cfa4498f640e0915b95fc806db4a0d54172fe8Jesse Wilson                    throw new IllegalArgumentException("dexcache == null (and no default could be"
46973cfa4498f640e0915b95fc806db4a0d54172fe8Jesse Wilson                            + " found; consider setting the 'dexmaker.dexcache' system property)");
47073cfa4498f640e0915b95fc806db4a0d54172fe8Jesse Wilson                }
47173cfa4498f640e0915b95fc806db4a0d54172fe8Jesse Wilson            }
47273cfa4498f640e0915b95fc806db4a0d54172fe8Jesse Wilson        }
47373cfa4498f640e0915b95fc806db4a0d54172fe8Jesse Wilson
474054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        File result = new File(dexCache, generateFileName());
475054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        // Check that the file exists. If it does, return a DexClassLoader and skip all
476054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        // the dex bytecode generation.
477054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        if (result.exists()) {
478171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann            return generateClassLoader(result, dexCache, parent);
479054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        }
480054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
481579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        byte[] dex = generate();
482579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
483579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
484579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * This implementation currently dumps the dex to the filesystem. It
485579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * jars the emitted .dex for the benefit of Gingerbread and earlier
486579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * devices, which can't load .dex files directly.
487579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *
488579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * TODO: load the dex from memory where supported.
489579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
490054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        result.createNewFile();
491579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        JarOutputStream jarOut = new JarOutputStream(new FileOutputStream(result));
4925999ddea21d4d5887cecdcb7730b0d16cdc54d93Andreas Gampe        JarEntry entry = new JarEntry(DexFormat.DEX_IN_JAR_NAME);
4935999ddea21d4d5887cecdcb7730b0d16cdc54d93Andreas Gampe        entry.setSize(dex.length);
4945999ddea21d4d5887cecdcb7730b0d16cdc54d93Andreas Gampe        jarOut.putNextEntry(entry);
495579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        jarOut.write(dex);
496579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        jarOut.closeEntry();
497579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        jarOut.close();
498171f097997993b84053f643dc275ce66364315caPhilip P. Moltmann        return generateClassLoader(result, dexCache, parent);
499579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
500579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
501d4a20568bcbaa34526676e4758e011ea32784825Philip P. Moltmann    DexFile getDexFile() {
502d4a20568bcbaa34526676e4758e011ea32784825Philip P. Moltmann        if (outputDex == null) {
503d4a20568bcbaa34526676e4758e011ea32784825Philip P. Moltmann            DexOptions options = new DexOptions();
504d4a20568bcbaa34526676e4758e011ea32784825Philip P. Moltmann            options.targetApiLevel = DexFormat.API_NO_EXTENDED_OPCODES;
505d4a20568bcbaa34526676e4758e011ea32784825Philip P. Moltmann            outputDex = new DexFile(options);
506d4a20568bcbaa34526676e4758e011ea32784825Philip P. Moltmann        }
507d4a20568bcbaa34526676e4758e011ea32784825Philip P. Moltmann        return outputDex;
508d4a20568bcbaa34526676e4758e011ea32784825Philip P. Moltmann    }
509d4a20568bcbaa34526676e4758e011ea32784825Philip P. Moltmann
510d4a20568bcbaa34526676e4758e011ea32784825Philip P. Moltmann    static class TypeDeclaration {
5110e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        private final TypeId<?> type;
512579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
513579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** declared state */
514579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private boolean declared;
515579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private int flags;
5160e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        private TypeId<?> supertype;
517579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private String sourceFile;
518579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private TypeList interfaces;
519d4a20568bcbaa34526676e4758e011ea32784825Philip P. Moltmann        private ClassDefItem classDefItem;
520579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
521b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        private final Map<FieldId, FieldDeclaration> fields = new LinkedHashMap<>();
522b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin        private final Map<MethodId, MethodDeclaration> methods = new LinkedHashMap<>();
523579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
5240e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        TypeDeclaration(TypeId<?> type) {
525579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            this.type = type;
526579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
527579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
528579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        ClassDefItem toClassDefItem() {
529579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (!declared) {
530579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                throw new IllegalStateException("Undeclared type " + type + " declares members: "
531579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        + fields.keySet() + " " + methods.keySet());
532579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
533579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
534579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            DexOptions dexOptions = new DexOptions();
535579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            dexOptions.targetApiLevel = DexFormat.API_NO_EXTENDED_OPCODES;
536579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
537579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            CstType thisType = type.constant;
538579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
539d4a20568bcbaa34526676e4758e011ea32784825Philip P. Moltmann            if (classDefItem == null) {
540d4a20568bcbaa34526676e4758e011ea32784825Philip P. Moltmann                classDefItem = new ClassDefItem(thisType, flags, supertype.constant,
541d4a20568bcbaa34526676e4758e011ea32784825Philip P. Moltmann                        interfaces.ropTypes, new CstString(sourceFile));
542d4a20568bcbaa34526676e4758e011ea32784825Philip P. Moltmann
543d4a20568bcbaa34526676e4758e011ea32784825Philip P. Moltmann                for (MethodDeclaration method : methods.values()) {
544d4a20568bcbaa34526676e4758e011ea32784825Philip P. Moltmann                    EncodedMethod encoded = method.toEncodedMethod(dexOptions);
545d4a20568bcbaa34526676e4758e011ea32784825Philip P. Moltmann                    if (method.isDirect()) {
546d4a20568bcbaa34526676e4758e011ea32784825Philip P. Moltmann                        classDefItem.addDirectMethod(encoded);
547d4a20568bcbaa34526676e4758e011ea32784825Philip P. Moltmann                    } else {
548d4a20568bcbaa34526676e4758e011ea32784825Philip P. Moltmann                        classDefItem.addVirtualMethod(encoded);
549d4a20568bcbaa34526676e4758e011ea32784825Philip P. Moltmann                    }
550579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
551d4a20568bcbaa34526676e4758e011ea32784825Philip P. Moltmann                for (FieldDeclaration field : fields.values()) {
552d4a20568bcbaa34526676e4758e011ea32784825Philip P. Moltmann                    EncodedField encoded = field.toEncodedField();
553d4a20568bcbaa34526676e4758e011ea32784825Philip P. Moltmann                    if (field.isStatic()) {
554d4a20568bcbaa34526676e4758e011ea32784825Philip P. Moltmann                        classDefItem.addStaticField(encoded, Constants.getConstant(field.staticValue));
555d4a20568bcbaa34526676e4758e011ea32784825Philip P. Moltmann                    } else {
556d4a20568bcbaa34526676e4758e011ea32784825Philip P. Moltmann                        classDefItem.addInstanceField(encoded);
557d4a20568bcbaa34526676e4758e011ea32784825Philip P. Moltmann                    }
558579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
559579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
560579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
561d4a20568bcbaa34526676e4758e011ea32784825Philip P. Moltmann            return classDefItem;
562579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
563579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
564579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
565579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    static class FieldDeclaration {
566579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        final FieldId<?, ?> fieldId;
567579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private final int accessFlags;
568579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private final Object staticValue;
569579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
570579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        FieldDeclaration(FieldId<?, ?> fieldId, int accessFlags, Object staticValue) {
57190699b97998f1582a921202fb909f17f9718d177Jesse Wilson            if ((accessFlags & STATIC) == 0 && staticValue != null) {
572579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                throw new IllegalArgumentException("instance fields may not have a value");
573579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
574579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            this.fieldId = fieldId;
575579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            this.accessFlags = accessFlags;
576579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            this.staticValue = staticValue;
577579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
578579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
579579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        EncodedField toEncodedField() {
580579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return new EncodedField(fieldId.constant, accessFlags);
581579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
582579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
583579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public boolean isStatic() {
58490699b97998f1582a921202fb909f17f9718d177Jesse Wilson            return (accessFlags & STATIC) != 0;
585579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
586579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
587579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
588579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    static class MethodDeclaration {
589579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        final MethodId<?, ?> method;
590579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private final int flags;
591579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private final Code code;
592579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
593579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public MethodDeclaration(MethodId<?, ?> method, int flags) {
594579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            this.method = method;
595579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            this.flags = flags;
596579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            this.code = new Code(this);
597579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
598579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
599579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        boolean isStatic() {
60090699b97998f1582a921202fb909f17f9718d177Jesse Wilson            return (flags & STATIC) != 0;
601579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
602579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
603579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        boolean isDirect() {
60490699b97998f1582a921202fb909f17f9718d177Jesse Wilson            return (flags & (STATIC | PRIVATE | ACC_CONSTRUCTOR)) != 0;
605579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
606579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
607579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        EncodedMethod toEncodedMethod(DexOptions dexOptions) {
608579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            RopMethod ropMethod = new RopMethod(code.toBasicBlocks(), 0);
609579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            LocalVariableInfo locals = null;
610579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            DalvCode dalvCode = RopTranslator.translate(
611579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    ropMethod, PositionList.NONE, locals, code.paramSize(), dexOptions);
612579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return new EncodedMethod(method.constant, flags, dalvCode, StdTypeList.EMPTY);
613579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
614579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
615579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson}
616