diff options
author | Jesse Wilson <jessewilson@google.com> | 2012-01-06 11:14:53 -0500 |
---|---|---|
committer | Jesse Wilson <jessewilson@google.com> | 2012-01-06 11:14:53 -0500 |
commit | 0e49fb9243b7463835ab80ef7cc62435f55846ce (patch) | |
tree | 6caa9d3c45c88f0fc695633d54a36c91fee70748 | |
parent | ab220f004db90fa94ef9349ca1adde5f89012e8d (diff) | |
download | dexmaker-0e49fb9243b7463835ab80ef7cc62435f55846ce.tar.gz |
Add a big example in DexMaker on its use. Also fix up some of the problems encountered while writing the example:
- Type should be TypeId
- Result targets should be in a consistent position in the instruction parameter list. I decided to go with first because methods have parameters in varargs that must be last.
-rw-r--r-- | src/main/java/com/google/dexmaker/Code.java | 52 | ||||
-rw-r--r-- | src/main/java/com/google/dexmaker/Constants.java | 8 | ||||
-rw-r--r-- | src/main/java/com/google/dexmaker/DexMaker.java | 163 | ||||
-rw-r--r-- | src/main/java/com/google/dexmaker/FieldId.java | 10 | ||||
-rw-r--r-- | src/main/java/com/google/dexmaker/Local.java | 8 | ||||
-rw-r--r-- | src/main/java/com/google/dexmaker/MethodId.java | 14 | ||||
-rw-r--r-- | src/main/java/com/google/dexmaker/TypeId.java (renamed from src/main/java/com/google/dexmaker/Type.java) | 54 | ||||
-rw-r--r-- | src/main/java/com/google/dexmaker/TypeList.java | 6 | ||||
-rw-r--r-- | src/main/java/com/google/dexmaker/stock/ProxyBuilder.java | 91 | ||||
-rw-r--r-- | src/test/java/com/google/dexmaker/DexMakerTest.java | 328 | ||||
-rw-r--r-- | src/test/java/com/google/dexmaker/TypeIdTest.java (renamed from src/test/java/com/google/dexmaker/TypeTest.java) | 14 | ||||
-rw-r--r-- | src/test/java/com/google/dexmaker/examples/FibonacciMaker.java | 74 |
12 files changed, 523 insertions, 299 deletions
diff --git a/src/main/java/com/google/dexmaker/Code.java b/src/main/java/com/google/dexmaker/Code.java index 7d8c492..4ec2782 100644 --- a/src/main/java/com/google/dexmaker/Code.java +++ b/src/main/java/com/google/dexmaker/Code.java @@ -69,7 +69,7 @@ public final class Code { private final List<Local<?>> parameters = new ArrayList<Local<?>>(); private final List<Local<?>> locals = new ArrayList<Local<?>>(); private SourcePosition sourcePosition = SourcePosition.NO_INFO; - private final List<Type<?>> catchTypes = new ArrayList<Type<?>>(); + private final List<TypeId<?>> catchTypes = new ArrayList<TypeId<?>>(); private final List<Label> catchLabels = new ArrayList<Label>(); private StdTypeList catches = StdTypeList.EMPTY; @@ -81,14 +81,14 @@ public final class Code { thisLocal = Local.get(this, method.declaringType); parameters.add(thisLocal); } - for (Type<?> parameter : method.parameters.types) { + for (TypeId<?> parameter : method.parameters.types) { parameters.add(Local.get(this, parameter)); } this.currentLabel = newLabel(); this.currentLabel.marked = true; } - public <T> Local<T> newLocal(Type<T> type) { + public <T> Local<T> newLocal(TypeId<T> type) { if (localsInitialized) { throw new IllegalStateException("Cannot allocate locals after adding instructions"); } @@ -97,14 +97,14 @@ public final class Code { return result; } - public <T> Local<T> getParameter(int index, Type<T> type) { + public <T> Local<T> getParameter(int index, TypeId<T> type) { if (thisLocal != null) { index++; // adjust for the hidden 'this' parameter } return coerce(parameters.get(index), type); } - public <T> Local<T> getThis(Type<T> type) { + public <T> Local<T> getThis(TypeId<T> type) { if (thisLocal == null) { throw new IllegalStateException("static methods cannot access 'this'"); } @@ -112,7 +112,7 @@ public final class Code { } @SuppressWarnings("unchecked") // guarded by an equals check - private <T> Local<T> coerce(Local<?> local, Type<T> expectedType) { + private <T> Local<T> coerce(Local<?> local, TypeId<T> expectedType) { if (!local.type.equals(expectedType)) { throw new IllegalArgumentException( "requested " + expectedType + " but was " + local.type); @@ -195,7 +195,7 @@ public final class Code { target); } - public void addCatchClause(Type<?> throwable, Label catchClause) { + public void addCatchClause(TypeId<?> throwable, Label catchClause) { if (catchTypes.contains(throwable)) { throw new IllegalArgumentException("Already caught: " + throwable); } @@ -204,7 +204,7 @@ public final class Code { catchLabels.add(catchClause); } - public Label removeCatchClause(Type<?> throwable) { + public Label removeCatchClause(TypeId<?> throwable) { int index = catchTypes.indexOf(throwable); if (index == -1) { throw new IllegalArgumentException("No catch clause: " + throwable); @@ -219,7 +219,7 @@ public final class Code { RegisterSpecList.make(throwable.spec()), catches)); } - private StdTypeList toTypeList(List<Type<?>> types) { + private StdTypeList toTypeList(List<TypeId<?>> types) { StdTypeList result = new StdTypeList(types.size()); for (int i = 0; i < types.size(); i++) { result.set(i, types.get(i).ropType); @@ -314,16 +314,16 @@ public final class Code { // instructions: unary - public <T> void negate(Local<T> source, Local<T> target) { - unary(Rops.opNeg(source.type.ropType), source, target); + public <T> void negate(Local<T> target, Local<T> source) { + unary(Rops.opNeg(source.type.ropType), target, source); } - public <T> void not(Local<T> source, Local<T> target) { - unary(Rops.opNot(source.type.ropType), source, target); + public <T> void not(Local<T> target, Local<T> source) { + unary(Rops.opNot(source.type.ropType), target, source); } - public void numericCast(Local<?> source, Local<?> target) { - unary(getCastRop(source.type.ropType, target.type.ropType), source, target); + public void numericCast(Local<?> target, Local<?> source) { + unary(getCastRop(source.type.ropType, target.type.ropType), target, source); } private Rop getCastRop(com.android.dx.rop.type.Type sourceType, @@ -341,7 +341,7 @@ public final class Code { return Rops.opConv(targetType, sourceType); } - private void unary(Rop rop, Local<?> source, Local<?> target) { + private void unary(Rop rop, Local<?> target, Local<?> source) { addInstruction(new PlainInsn(rop, sourcePosition, target.spec(), source.spec())); } @@ -365,7 +365,7 @@ public final class Code { * Compare ints. If the comparison is true, execution jumps to {@code * trueLabel}. If it is false, execution continues to the next instruction. */ - public <T> void compare(Comparison comparison, Local<T> a, Local<T> b, Label trueLabel) { + public <T> void compare(Comparison comparison, Label trueLabel, Local<T> a, Local<T> b) { if (trueLabel == null) { throw new IllegalArgumentException(); } @@ -377,7 +377,7 @@ public final class Code { /** * Compare floats or doubles. */ - public <T extends Number> void compare(Local<T> a, Local<T> b, Local<Integer> target, + public <T extends Number> void compare(Local<Integer> target, Local<T> a, Local<T> b, int nanValue) { Rop rop; if (nanValue == 1) { @@ -394,14 +394,14 @@ public final class Code { /** * Compare longs. */ - public <T> void compare(Local<T> a, Local<T> b, Local<?> target) { + public <T> void compare(Local<?> target, Local<T> a, Local<T> b) { addInstruction(new PlainInsn(Rops.CMPL_LONG, sourcePosition, target.spec(), RegisterSpecList.make(a.spec(), b.spec()))); } // instructions: fields - public <D, V> void iget(FieldId<D, V> fieldId, Local<D> instance, Local<V> target) { + public <D, V> void iget(FieldId<D, V> fieldId, Local<V> target, Local<D> instance) { addInstruction(new ThrowingCstInsn(Rops.opGetField(target.type.ropType), sourcePosition, RegisterSpecList.make(instance.spec()), catches, fieldId.constant)); moveResult(target, true); @@ -470,13 +470,13 @@ public final class Code { // instructions: types - public void instanceOfType(Local<?> target, Local<?> source, Type<?> type) { + public void instanceOfType(Local<?> target, Local<?> source, TypeId<?> type) { addInstruction(new ThrowingCstInsn(Rops.INSTANCE_OF, sourcePosition, RegisterSpecList.make(source.spec()), catches, type.constant)); moveResult(target, true); } - public void typeCast(Local<?> source, Local<?> target) { + public void typeCast(Local<?> target, Local<?> source) { addInstruction(new ThrowingCstInsn(Rops.CHECK_CAST, sourcePosition, RegisterSpecList.make(source.spec()), catches, target.type.constant)); moveResult(target, true); @@ -484,19 +484,19 @@ public final class Code { // instructions: arrays - public <T> void arrayLength(Local<T> array, Local<Integer> target) { + public <T> void arrayLength(Local<Integer> target, Local<T> array) { addInstruction(new ThrowingInsn(Rops.ARRAY_LENGTH, sourcePosition, RegisterSpecList.make(array.spec()), catches)); moveResult(target, true); } - public <T> void newArray(Local<Integer> length, Local<T> target) { + public <T> void newArray(Local<T> target, Local<Integer> length) { addInstruction(new ThrowingCstInsn(Rops.opNewArray(target.type.ropType), sourcePosition, RegisterSpecList.make(length.spec()), catches, target.type.constant)); moveResult(target, true); } - public void aget(Local<?> array, Local<Integer> index, Local<?> target) { + public void aget(Local<?> target, Local<?> array, Local<Integer> index) { addInstruction(new ThrowingInsn(Rops.opAget(target.type.ropType), sourcePosition, RegisterSpecList.make(array.spec(), index.spec()), catches)); moveResult(target, true); @@ -510,7 +510,7 @@ public final class Code { // instructions: return public void returnVoid() { - if (!method.returnType.equals(Type.VOID)) { + if (!method.returnType.equals(TypeId.VOID)) { throw new IllegalArgumentException("declared " + method.returnType + " but returned void"); } diff --git a/src/main/java/com/google/dexmaker/Constants.java b/src/main/java/com/google/dexmaker/Constants.java index fd9bbf1..ec21cb8 100644 --- a/src/main/java/com/google/dexmaker/Constants.java +++ b/src/main/java/com/google/dexmaker/Constants.java @@ -38,7 +38,7 @@ final class Constants { /** * Returns a rop constant for the specified value. * - * @param value null, a boxed primitive, String, Class, or Type. + * @param value null, a boxed primitive, String, Class, or TypeId. */ static TypedConstant getConstant(Object value) { if (value == null) { @@ -62,9 +62,9 @@ final class Constants { } else if (value instanceof String) { return new CstString((String) value); } else if (value instanceof Class) { - return new CstType(Type.get((Class<?>) value).ropType); - } else if (value instanceof Type) { - return new CstType(((Type) value).ropType); + return new CstType(TypeId.get((Class<?>) value).ropType); + } else if (value instanceof TypeId) { + return new CstType(((TypeId) value).ropType); } else { throw new UnsupportedOperationException("Not a constant: " + value); } diff --git a/src/main/java/com/google/dexmaker/DexMaker.java b/src/main/java/com/google/dexmaker/DexMaker.java index a40ab85..11b584b 100644 --- a/src/main/java/com/google/dexmaker/DexMaker.java +++ b/src/main/java/com/google/dexmaker/DexMaker.java @@ -44,13 +44,155 @@ import java.util.jar.JarEntry; import java.util.jar.JarOutputStream; /** - * Define types, fields and methods. + * Generates a </i><strong>D</strong>alvik <strong>EX</strong>ecutable (dex) + * file for execution on Android. dex files defines classes and interfaces, + * including their member methods and fields, executable code, and debugging + * information. They also define annotations, though this API currently has no + * facility to create a dex file that contains annotations. + * + * <p>This library is intended to satisfy two use cases: + * <ul> + * <li><strong>For runtime code generation.</strong> By embedding this library + * in your Android application, you can dynamically generate and load + * executable code. This approach takes advantage of the fact that the + * host environment and target environment are both Android. + * <li><strong>For compile time code generation.</strong> You may use this + * library as a part of a compiler that targets Android. In this scenario + * the generated dex file must be installed on an Android device before it + * can be executed. + * </ul> + * + * <h3>Example: Fibonacci</h3> + * To illustrate how this API is used, we'll use DexMaker to generate a class + * equivalent to the following Java source: <pre> {@code + * + * package com.publicobject.fib; + * + * public class Fibonacci { + * public static int fib(int i) { + * if (i < 2) { + * return i; + * } + * return fib(i - 1) + fib(i - 2); + * } + * }}</pre> + * + * <p>We start by creating a {@link TypeId} to identify the generated {@code + * Fibonacci} class. DexMaker identifies types by their internal names like + * {@code Ljava/lang/Object;} rather than their Java identifiers like {@code + * java.lang.Object}. <pre> {@code + * + * TypeId<?> fibonacci = TypeId.get("Lcom/google/dexmaker/examples/Fibonacci;"); + * }</pre> + * + * <p>Next we declare the class. It allows us to specify the type's source file + * for stack traces, its modifiers, its superclass, and the interfaces it + * implements. In this case, {@code Fibonacci} is a public class that extends + * from {@code Object}: <pre> {@code + * + * String fileName = "Fibonacci.generated"; + * DexMaker dexMaker = new DexMaker(); + * dexMaker.declare(fibonacci, fileName, Modifier.PUBLIC, TypeId.OBJECT); + * }</pre> + * It is illegal to declare members of a class without also declaring the class + * itself. + * + * <p>To make it easier to go from our Java method to dex instructions, we'll + * manually translate it to pseudocode fit for an assembler. We need to replace + * control flow like {@code if()} blocks and {@code for()} loops with labels and + * branches. We'll also avoid performing multiple operations in one statement, + * using local variables to hold intermediate values as necessary: + * <pre> {@code + * + * int constant1 = 1; + * int constant2 = 2; + * if (i < constant2) goto baseCase; + * int a = i - constant1; + * int b = i - constant2; + * int c = fib(a); + * int d = fib(b); + * int result = c + d; + * return result; + * baseCase: + * return i; + * }</pre> + * + * <p>We lookup the {@code MethodId} for the method on the declaring type. This + * takes the method's return type (possibly {@link TypeId#VOID}), its name, and + * its parameters. Next we declare the method, specifying its modifiers by ORing + * constants from {@link java.lang.reflect.Modifier}. The declare call returns a + * {@link Code} object, which we'll use to define the method's instructions. + * <pre> {@code + * + * MethodId<?, Integer> fib = fibonacci.getMethod(TypeId.INT, "fib", TypeId.INT); + * Code code = dexMaker.declare(fib, Modifier.PUBLIC | Modifier.STATIC); + * }</pre> + * + * <p>One limitation of {@code DexMaker}'s API is that it requires all local + * variables to be created before any instructions are emitted. Use {@link + * Code#newLocal} to create a new local variable. The method's parameters are + * exposed as locals using {@link Code#getParameter}. For non-static methods the + * 'this' pointer is exposed using {@link Code#getThis}. Here we declare all of + * the local variables that we'll need for our {@code fib()} method: + * <pre> {@code + * + * Local<Integer> i = code.getParameter(0, TypeId.INT); + * Local<Integer> constant1 = code.newLocal(TypeId.INT); + * Local<Integer> constant2 = code.newLocal(TypeId.INT); + * Local<Integer> a = code.newLocal(TypeId.INT); + * Local<Integer> b = code.newLocal(TypeId.INT); + * Local<Integer> c = code.newLocal(TypeId.INT); + * Local<Integer> d = code.newLocal(TypeId.INT); + * Local<Integer> result = code.newLocal(TypeId.INT); + * }</pre> + * + * <p>Notice that {@link Local} has a type parameter. This is useful for + * generating code that works with existing types like {@code String} and {@code + * Integer}, but it can be a hindrance when generating code that involves new + * types. For this reason you may prefer to use raw types only and add + * {@code @SuppressWarnings("unsafe")} on your calling code. This will yield the + * same result but you won't get a compiler warning if you make a type error. + * + * <p>We're ready to start defining our method's instructions: <pre> {@code + * + * code.loadConstant(constant1, 1); + * code.loadConstant(constant2, 2); + * Label baseCase = code.newLabel(); + * code.compare(Comparison.LT, baseCase, i, constant2); + * code.op(BinaryOp.SUBTRACT, a, i, constant1); + * code.op(BinaryOp.SUBTRACT, b, i, constant2); + * code.invokeStatic(fib, c, a); + * code.invokeStatic(fib, d, b); + * code.op(BinaryOp.ADD, result, c, d); + * code.returnValue(result); + * code.mark(baseCase); + * code.returnValue(i); + * }</pre> + * + * <p>We're done defining the instructions! We just need to write the dex to the + * file system or load it into the current process. For this example we'll load + * the generated code into the current process. This only works when the current + * process is running on Android. We use {@link #generateAndLoad} which takes + * the class loader that will be used as our generated code's parent class + * loader. It also requires two paths where temporary files may be written. + * <pre> {@code + * + * ClassLoader loader = dexMaker.generateAndLoad( + * Fibonacci.class.getClassLoader(), getDataDirectory(), getDataDirectory()); + * }</pre> + * Finally we'll use reflection to lookup our generated class on its class + * loader and invoke its {@code fib()} method: <pre> {@code + * + * Class<?> fibonacciClass = loader.loadClass("com.google.dexmaker.examples.Fibonacci"); + * Method fibMethod = fibonacciClass.getMethod("fib", int.class); + * System.out.println(fibMethod.invoke(null, 8)); + * }</pre> */ public final class DexMaker { - private final Map<Type<?>, TypeDeclaration> types - = new LinkedHashMap<Type<?>, TypeDeclaration>(); + private final Map<TypeId<?>, TypeDeclaration> types + = new LinkedHashMap<TypeId<?>, TypeDeclaration>(); - private TypeDeclaration getTypeDeclaration(Type<?> type) { + private TypeDeclaration getTypeDeclaration(TypeId<?> type) { TypeDeclaration result = types.get(type); if (result == null) { result = new TypeDeclaration(type); @@ -64,8 +206,8 @@ public final class DexMaker { /** * @param flags any flags masked by {@link com.android.dx.rop.code.AccessFlags#CLASS_FLAGS}. */ - public void declare(Type<?> type, String sourceFile, int flags, - Type<?> supertype, Type<?>... interfaces) { + public void declare(TypeId<?> type, String sourceFile, int flags, + TypeId<?> supertype, TypeId<?>... interfaces) { TypeDeclaration declaration = getTypeDeclaration(type); if (declaration.declared) { throw new IllegalStateException("already declared: " + type); @@ -146,7 +288,8 @@ public final class DexMaker { * emitted .dex files before they end up in the cache directory * @param dexOptCacheDir where optimized .dex files are to be written */ - public ClassLoader load(ClassLoader parent, File dexOutputDir, File dexOptCacheDir) + // TODO: why two directories? + public ClassLoader generateAndLoad(ClassLoader parent, File dexOutputDir, File dexOptCacheDir) throws IOException { byte[] dex = generate(); @@ -182,12 +325,12 @@ public final class DexMaker { } private static class TypeDeclaration { - private final Type<?> type; + private final TypeId<?> type; /** declared state */ private boolean declared; private int flags; - private Type<?> supertype; + private TypeId<?> supertype; private String sourceFile; private TypeList interfaces; @@ -196,7 +339,7 @@ public final class DexMaker { private final Map<MethodId, MethodDeclaration> methods = new LinkedHashMap<MethodId, MethodDeclaration>(); - TypeDeclaration(Type<?> type) { + TypeDeclaration(TypeId<?> type) { this.type = type; } diff --git a/src/main/java/com/google/dexmaker/FieldId.java b/src/main/java/com/google/dexmaker/FieldId.java index 75f1809..17ebfec 100644 --- a/src/main/java/com/google/dexmaker/FieldId.java +++ b/src/main/java/com/google/dexmaker/FieldId.java @@ -24,15 +24,15 @@ import com.android.dx.rop.cst.CstString; * A field. */ public final class FieldId<D, V> { - final Type<D> declaringType; - final Type<V> type; + final TypeId<D> declaringType; + final TypeId<V> type; final String name; /** cached converted state */ final CstNat nat; final CstFieldRef constant; - FieldId(Type<D> declaringType, Type<V> type, String name) { + FieldId(TypeId<D> declaringType, TypeId<V> type, String name) { if (declaringType == null || type == null || name == null) { throw new NullPointerException(); } @@ -43,11 +43,11 @@ public final class FieldId<D, V> { this.constant = new CstFieldRef(declaringType.constant, nat); } - public Type<D> getDeclaringType() { + public TypeId<D> getDeclaringType() { return declaringType; } - public Type<V> getType() { + public TypeId<V> getType() { return type; } diff --git a/src/main/java/com/google/dexmaker/Local.java b/src/main/java/com/google/dexmaker/Local.java index 05f5a25..a993d5f 100644 --- a/src/main/java/com/google/dexmaker/Local.java +++ b/src/main/java/com/google/dexmaker/Local.java @@ -23,16 +23,16 @@ import com.android.dx.rop.code.RegisterSpec; */ public final class Local<T> { private final Code code; - final Type<T> type; + final TypeId<T> type; private int reg = -1; private RegisterSpec spec; - private Local(Code code, Type<T> type) { + private Local(Code code, TypeId<T> type) { this.code = code; this.type = type; } - static <T> Local<T> get(Code code, Type<T> type) { + static <T> Local<T> get(Code code, TypeId<T> type) { return new Local<T>(code, type); } @@ -64,7 +64,7 @@ public final class Local<T> { return spec; } - public Type getType() { + public TypeId getType() { return type; } diff --git a/src/main/java/com/google/dexmaker/MethodId.java b/src/main/java/com/google/dexmaker/MethodId.java index 72103c4..ba67ff5 100644 --- a/src/main/java/com/google/dexmaker/MethodId.java +++ b/src/main/java/com/google/dexmaker/MethodId.java @@ -26,8 +26,8 @@ import java.util.List; * A method or constructor. */ public final class MethodId<D, R> { - final Type<D> declaringType; - final Type<R> returnType; + final TypeId<D> declaringType; + final TypeId<R> returnType; final String name; final TypeList parameters; @@ -35,7 +35,7 @@ public final class MethodId<D, R> { final CstNat nat; final CstMethodRef constant; - MethodId(Type<D> declaringType, Type<R> returnType, String name, TypeList parameters) { + MethodId(TypeId<D> declaringType, TypeId<R> returnType, String name, TypeList parameters) { if (declaringType == null || returnType == null || name == null || parameters == null) { throw new NullPointerException(); } @@ -47,11 +47,11 @@ public final class MethodId<D, R> { this.constant = new CstMethodRef(declaringType.constant, nat); } - public Type<D> getDeclaringType() { + public TypeId<D> getDeclaringType() { return declaringType; } - public Type<R> getReturnType() { + public TypeId<R> getReturnType() { return returnType; } @@ -59,7 +59,7 @@ public final class MethodId<D, R> { return name; } - public List<Type<?>> getParameters() { + public List<TypeId<?>> getParameters() { return parameters.asList(); } @@ -72,7 +72,7 @@ public final class MethodId<D, R> { if (includeThis) { result.append(declaringType.name); } - for (Type t : parameters.types) { + for (TypeId t : parameters.types) { result.append(t.name); } result.append(")"); diff --git a/src/main/java/com/google/dexmaker/Type.java b/src/main/java/com/google/dexmaker/TypeId.java index bc56bd0..42a5e0a 100644 --- a/src/main/java/com/google/dexmaker/Type.java +++ b/src/main/java/com/google/dexmaker/TypeId.java @@ -23,44 +23,44 @@ import java.util.Map; /** * A primitive type, interface or class. */ -public final class Type<T> { +public final class TypeId<T> { /** The {@code boolean} primitive type. */ - public static final Type<Boolean> BOOLEAN - = new Type<Boolean>(com.android.dx.rop.type.Type.BOOLEAN); + public static final TypeId<Boolean> BOOLEAN + = new TypeId<Boolean>(com.android.dx.rop.type.Type.BOOLEAN); /** The {@code byte} primitive type. */ - public static final Type<Byte> BYTE = new Type<Byte>(com.android.dx.rop.type.Type.BYTE); + public static final TypeId<Byte> BYTE = new TypeId<Byte>(com.android.dx.rop.type.Type.BYTE); /** The {@code char} primitive type. */ - public static final Type<Character> CHAR - = new Type<Character>(com.android.dx.rop.type.Type.CHAR); + public static final TypeId<Character> CHAR + = new TypeId<Character>(com.android.dx.rop.type.Type.CHAR); /** The {@code double} primitive type. */ - public static final Type<Double> DOUBLE = new Type<Double>(com.android.dx.rop.type.Type.DOUBLE); + public static final TypeId<Double> DOUBLE = new TypeId<Double>(com.android.dx.rop.type.Type.DOUBLE); /** The {@code float} primitive type. */ - public static final Type<Float> FLOAT = new Type<Float>(com.android.dx.rop.type.Type.FLOAT); + public static final TypeId<Float> FLOAT = new TypeId<Float>(com.android.dx.rop.type.Type.FLOAT); /** The {@code int} primitive type. */ - public static final Type<Integer> INT = new Type<Integer>(com.android.dx.rop.type.Type.INT); + public static final TypeId<Integer> INT = new TypeId<Integer>(com.android.dx.rop.type.Type.INT); /** The {@code long} primitive type. */ - public static final Type<Long> LONG = new Type<Long>(com.android.dx.rop.type.Type.LONG); + public static final TypeId<Long> LONG = new TypeId<Long>(com.android.dx.rop.type.Type.LONG); /** The {@code short} primitive type. */ - public static final Type<Short> SHORT = new Type<Short>(com.android.dx.rop.type.Type.SHORT); + public static final TypeId<Short> SHORT = new TypeId<Short>(com.android.dx.rop.type.Type.SHORT); /** The {@code void} primitive type. Only used as a return type. */ - public static final Type<Void> VOID = new Type<Void>(com.android.dx.rop.type.Type.VOID); + public static final TypeId<Void> VOID = new TypeId<Void>(com.android.dx.rop.type.Type.VOID); /** The {@code Object} type. */ - public static final Type<Object> OBJECT = new Type<Object>(com.android.dx.rop.type.Type.OBJECT); + public static final TypeId<Object> OBJECT = new TypeId<Object>(com.android.dx.rop.type.Type.OBJECT); /** The {@code String} type. */ - public static final Type<String> STRING = new Type<String>(com.android.dx.rop.type.Type.STRING); + public static final TypeId<String> STRING = new TypeId<String>(com.android.dx.rop.type.Type.STRING); - private static final Map<Class<?>, Type<?>> PRIMITIVE_TO_TYPE - = new HashMap<Class<?>, Type<?>>(); + private static final Map<Class<?>, TypeId<?>> PRIMITIVE_TO_TYPE + = new HashMap<Class<?>, TypeId<?>>(); static { PRIMITIVE_TO_TYPE.put(boolean.class, BOOLEAN); PRIMITIVE_TO_TYPE.put(byte.class, BYTE); @@ -79,11 +79,11 @@ public final class Type<T> { final com.android.dx.rop.type.Type ropType; final CstType constant; - Type(com.android.dx.rop.type.Type ropType) { + TypeId(com.android.dx.rop.type.Type ropType) { this(ropType.getDescriptor(), ropType); } - Type(String name, com.android.dx.rop.type.Type ropType) { + TypeId(String name, com.android.dx.rop.type.Type ropType) { if (name == null || ropType == null) { throw new NullPointerException(); } @@ -95,29 +95,29 @@ public final class Type<T> { /** * @param name a descriptor like "Ljava/lang/Class;". */ - public static <T> Type<T> get(String name) { - return new Type<T>(name, com.android.dx.rop.type.Type.internReturnType(name)); + public static <T> TypeId<T> get(String name) { + return new TypeId<T>(name, com.android.dx.rop.type.Type.internReturnType(name)); } - public static <T> Type<T> get(Class<T> type) { + public static <T> TypeId<T> get(Class<T> type) { if (type.isPrimitive()) { @SuppressWarnings("unchecked") // guarded by equals - Type<T> result = (Type<T>) PRIMITIVE_TO_TYPE.get(type); + TypeId<T> result = (TypeId<T>) PRIMITIVE_TO_TYPE.get(type); return result; } String name = type.getName().replace('.', '/'); return get(type.isArray() ? name : 'L' + name + ';'); } - public <V> FieldId<T, V> getField(Type<V> type, String name) { + public <V> FieldId<T, V> getField(TypeId<V> type, String name) { return new FieldId<T, V>(this, type, name); } - public MethodId<T, Void> getConstructor(Type<?>... parameters) { + public MethodId<T, Void> getConstructor(TypeId<?>... parameters) { return new MethodId<T, Void>(this, VOID, "<init>", new TypeList(parameters)); } - public <R> MethodId<T, R> getMethod(Type<R> returnType, String name, Type<?>... parameters) { + public <R> MethodId<T, R> getMethod(TypeId<R> returnType, String name, TypeId<?>... parameters) { return new MethodId<T, R>(this, returnType, name, new TypeList(parameters)); } @@ -126,8 +126,8 @@ public final class Type<T> { } @Override public boolean equals(Object o) { - return o instanceof Type - && ((Type) o).name.equals(name); + return o instanceof TypeId + && ((TypeId) o).name.equals(name); } @Override public int hashCode() { diff --git a/src/main/java/com/google/dexmaker/TypeList.java b/src/main/java/com/google/dexmaker/TypeList.java index 8a48564..688157f 100644 --- a/src/main/java/com/google/dexmaker/TypeList.java +++ b/src/main/java/com/google/dexmaker/TypeList.java @@ -25,10 +25,10 @@ import java.util.List; * An immutable of types. */ final class TypeList { - final Type<?>[] types; + final TypeId<?>[] types; final StdTypeList ropTypes; - TypeList(Type<?>[] types) { + TypeList(TypeId<?>[] types) { this.types = types.clone(); this.ropTypes = new StdTypeList(types.length); for (int i = 0; i < types.length; i++) { @@ -39,7 +39,7 @@ final class TypeList { /** * Returns an immutable list. */ - public List<Type<?>> asList() { + public List<TypeId<?>> asList() { return Collections.unmodifiableList(Arrays.asList(types)); } diff --git a/src/main/java/com/google/dexmaker/stock/ProxyBuilder.java b/src/main/java/com/google/dexmaker/stock/ProxyBuilder.java index 265b9a7..169e237 100644 --- a/src/main/java/com/google/dexmaker/stock/ProxyBuilder.java +++ b/src/main/java/com/google/dexmaker/stock/ProxyBuilder.java @@ -23,7 +23,7 @@ import com.google.dexmaker.FieldId; import com.google.dexmaker.Label; import com.google.dexmaker.Local; import com.google.dexmaker.MethodId; -import com.google.dexmaker.Type; +import com.google.dexmaker.TypeId; import java.io.File; import java.io.IOException; import java.lang.reflect.Constructor; @@ -117,6 +117,7 @@ public final class ProxyBuilder<T> { private static final String FIELD_NAME_METHODS = "$__methodArray"; private final Class<T> baseClass; + // TODO: make DexMaker do the defaulting here private ClassLoader parentClassLoader = ProxyBuilder.class.getClassLoader(); private InvocationHandler handler; private File dexCache; @@ -178,13 +179,13 @@ public final class ProxyBuilder<T> { "constructorArgValues.length != constructorArgTypes.length"); DexMaker dexMaker = new DexMaker(); String generatedName = getMethodNameForProxyOf(baseClass); - Type<? extends T> generatedType = Type.get("L" + generatedName + ";"); - Type<T> superType = Type.get(baseClass); + TypeId<? extends T> generatedType = TypeId.get("L" + generatedName + ";"); + TypeId<T> superType = TypeId.get(baseClass); generateConstructorsAndFields(dexMaker, generatedType, superType, baseClass); Method[] methodsToProxy = getMethodsToProxy(baseClass); generateCodeForAllMethods(dexMaker, generatedType, methodsToProxy, superType); dexMaker.declare(generatedType, generatedName + ".generated", PUBLIC, superType); - ClassLoader classLoader = dexMaker.load(parentClassLoader, dexCache, dexCache); + ClassLoader classLoader = dexMaker.generateAndLoad(parentClassLoader, dexCache, dexCache); Class<? extends T> proxyClass; try { proxyClass = loadClass(classLoader, generatedName); @@ -288,17 +289,17 @@ public final class ProxyBuilder<T> { } private static <T, G extends T> void generateCodeForAllMethods(DexMaker dexMaker, - Type<G> generatedType, Method[] methodsToProxy, Type<T> superclassType) { - Type<InvocationHandler> handlerType = Type.get(InvocationHandler.class); - Type<Method[]> methodArrayType = Type.get(Method[].class); + TypeId<G> generatedType, Method[] methodsToProxy, TypeId<T> superclassType) { + TypeId<InvocationHandler> handlerType = TypeId.get(InvocationHandler.class); + TypeId<Method[]> methodArrayType = TypeId.get(Method[].class); FieldId<G, InvocationHandler> handlerField = generatedType.getField(handlerType, FIELD_NAME_HANDLER); FieldId<G, Method[]> allMethods = generatedType.getField(methodArrayType, FIELD_NAME_METHODS); - Type<Method> methodType = Type.get(Method.class); - Type<Object[]> objectArrayType = Type.get(Object[].class); - MethodId<InvocationHandler, Object> methodInvoke = handlerType.getMethod(Type.OBJECT, - "invoke", Type.OBJECT, methodType, objectArrayType); + TypeId<Method> methodType = TypeId.get(Method.class); + TypeId<Object[]> objectArrayType = TypeId.get(Object[].class); + MethodId<InvocationHandler, Object> methodInvoke = handlerType.getMethod(TypeId.OBJECT, + "invoke", TypeId.OBJECT, methodType, objectArrayType); for (int m = 0; m < methodsToProxy.length; ++m) { /* * If the 5th method on the superclass Example that can be overridden were to look like @@ -346,30 +347,30 @@ public final class ProxyBuilder<T> { Method method = methodsToProxy[m]; String name = method.getName(); Class<?>[] argClasses = method.getParameterTypes(); - Type<?>[] argTypes = new Type<?>[argClasses.length]; + TypeId<?>[] argTypes = new TypeId<?>[argClasses.length]; for (int i = 0; i < argTypes.length; ++i) { - argTypes[i] = Type.get(argClasses[i]); + argTypes[i] = TypeId.get(argClasses[i]); } Class<?> returnType = method.getReturnType(); - Type<?> resultType = Type.get(returnType); + TypeId<?> resultType = TypeId.get(returnType); MethodId<T, ?> superMethod = superclassType.getMethod(resultType, name, argTypes); MethodId<?, ?> methodId = generatedType.getMethod(resultType, name, argTypes); Code code = dexMaker.declare(methodId, PUBLIC); Local<G> localThis = code.getThis(generatedType); Local<InvocationHandler> localHandler = code.newLocal(handlerType); - Local<Object> invokeResult = code.newLocal(Type.OBJECT); - Local<Integer> intValue = code.newLocal(Type.INT); + Local<Object> invokeResult = code.newLocal(TypeId.OBJECT); + Local<Integer> intValue = code.newLocal(TypeId.INT); Local<Object[]> args = code.newLocal(objectArrayType); - Local<Integer> argsLength = code.newLocal(Type.INT); - Local<Object> temp = code.newLocal(Type.OBJECT); + Local<Integer> argsLength = code.newLocal(TypeId.INT); + Local<Object> temp = code.newLocal(TypeId.OBJECT); Local<?> resultHolder = code.newLocal(resultType); Local<Method[]> methodArray = code.newLocal(methodArrayType); Local<Method> thisMethod = code.newLocal(methodType); - Local<Integer> methodIndex = code.newLocal(Type.INT); + Local<Integer> methodIndex = code.newLocal(TypeId.INT); Class<?> aBoxedClass = PRIMITIVE_TO_BOXED.get(returnType); Local<?> aBoxedResult = null; if (aBoxedClass != null) { - aBoxedResult = code.newLocal(Type.get(aBoxedClass)); + aBoxedResult = code.newLocal(TypeId.get(aBoxedClass)); } Local<?>[] superArgs2 = new Local<?>[argClasses.length]; Local<?> superResult2 = code.newLocal(resultType); @@ -377,15 +378,15 @@ public final class ProxyBuilder<T> { code.loadConstant(methodIndex, m); code.sget(allMethods, methodArray); - code.aget(methodArray, methodIndex, thisMethod); + code.aget(thisMethod, methodArray, methodIndex); code.loadConstant(argsLength, argTypes.length); - code.newArray(argsLength, args); - code.iget(handlerField, localThis, localHandler); + code.newArray(args, argsLength); + code.iget(handlerField, localHandler, localThis); // if (proxy == null) code.loadConstant(nullHandler, null); Label handlerNullCase = code.newLabel(); - code.compare(Comparison.EQ, nullHandler, localHandler, handlerNullCase); + code.compare(Comparison.EQ, handlerNullCase, nullHandler, localHandler); // This code is what we execute when we have a valid proxy: delegate to invocation // handler. @@ -473,9 +474,9 @@ public final class ProxyBuilder<T> { } private static <T, G extends T> void generateConstructorsAndFields(DexMaker dexMaker, - Type<G> generatedType, Type<T> superType, Class<T> superClass) { - Type<InvocationHandler> handlerType = Type.get(InvocationHandler.class); - Type<Method[]> methodArrayType = Type.get(Method[].class); + TypeId<G> generatedType, TypeId<T> superType, Class<T> superClass) { + TypeId<InvocationHandler> handlerType = TypeId.get(InvocationHandler.class); + TypeId<Method[]> methodArrayType = TypeId.get(Method[].class); FieldId<G, InvocationHandler> handlerField = generatedType.getField( handlerType, FIELD_NAME_HANDLER); dexMaker.declare(handlerField, PRIVATE, null); @@ -486,7 +487,7 @@ public final class ProxyBuilder<T> { if (constructor.getModifiers() == Modifier.FINAL) { continue; } - Type<?>[] types = classArrayToTypeArray(constructor.getParameterTypes()); + TypeId<?>[] types = classArrayToTypeArray(constructor.getParameterTypes()); MethodId<?, ?> method = generatedType.getConstructor(types); Code constructorCode = dexMaker.declareConstructor(method, PUBLIC); Local<G> thisRef = constructorCode.getThis(generatedType); @@ -542,10 +543,10 @@ public final class ProxyBuilder<T> { return clazz.getSimpleName() + "_Proxy"; } - private static Type<?>[] classArrayToTypeArray(Class<?>[] input) { - Type<?>[] result = new Type[input.length]; + private static TypeId<?>[] classArrayToTypeArray(Class<?>[] input) { + TypeId<?>[] result = new TypeId[input.length]; for (int i = 0; i < input.length; ++i) { - result[i] = Type.get(input[i]); + result[i] = TypeId.get(input[i]); } return result; } @@ -561,14 +562,14 @@ public final class ProxyBuilder<T> { private static void generateCodeForReturnStatement(Code code, Class methodReturnType, Local localForResultOfInvoke, Local localOfMethodReturnType, Local aBoxedResult) { if (PRIMITIVE_TO_UNBOX_METHOD.containsKey(methodReturnType)) { - code.typeCast(localForResultOfInvoke, aBoxedResult); + code.typeCast(aBoxedResult, localForResultOfInvoke); MethodId unboxingMethodFor = getUnboxMethodForPrimitive(methodReturnType); code.invokeVirtual(unboxingMethodFor, localOfMethodReturnType, aBoxedResult); code.returnValue(localOfMethodReturnType); } else if (void.class.equals(methodReturnType)) { code.returnVoid(); } else { - code.typeCast(localForResultOfInvoke, localOfMethodReturnType); + code.typeCast(localOfMethodReturnType, localForResultOfInvoke); code.returnValue(localOfMethodReturnType); } } @@ -590,12 +591,12 @@ public final class ProxyBuilder<T> { PRIMITIVE_TO_BOXED.put(char.class, Character.class); } - private static final Map<Type<?>, MethodId<?, ?>> PRIMITIVE_TYPE_TO_UNBOX_METHOD; + private static final Map<TypeId<?>, MethodId<?, ?>> PRIMITIVE_TYPE_TO_UNBOX_METHOD; static { - PRIMITIVE_TYPE_TO_UNBOX_METHOD = new HashMap<Type<?>, MethodId<?, ?>>(); + PRIMITIVE_TYPE_TO_UNBOX_METHOD = new HashMap<TypeId<?>, MethodId<?, ?>>(); for (Map.Entry<Class<?>, Class<?>> entry : PRIMITIVE_TO_BOXED.entrySet()) { - Type<?> primitiveType = Type.get(entry.getKey()); - Type<?> boxedType = Type.get(entry.getValue()); + TypeId<?> primitiveType = TypeId.get(entry.getKey()); + TypeId<?> boxedType = TypeId.get(entry.getValue()); MethodId<?, ?> valueOfMethod = boxedType.getMethod(boxedType, "valueOf", primitiveType); PRIMITIVE_TYPE_TO_UNBOX_METHOD.put(primitiveType, valueOfMethod); } @@ -611,14 +612,14 @@ public final class ProxyBuilder<T> { private static final Map<Class<?>, MethodId<?, ?>> PRIMITIVE_TO_UNBOX_METHOD; static { Map<Class<?>, MethodId<?, ?>> map = new HashMap<Class<?>, MethodId<?, ?>>(); - map.put(boolean.class, Type.get(Boolean.class).getMethod(Type.BOOLEAN, "booleanValue")); - map.put(int.class, Type.get(Integer.class).getMethod(Type.INT, "intValue")); - map.put(byte.class, Type.get(Byte.class).getMethod(Type.BYTE, "byteValue")); - map.put(long.class, Type.get(Long.class).getMethod(Type.LONG, "longValue")); - map.put(short.class, Type.get(Short.class).getMethod(Type.SHORT, "shortValue")); - map.put(float.class, Type.get(Float.class).getMethod(Type.FLOAT, "floatValue")); - map.put(double.class, Type.get(Double.class).getMethod(Type.DOUBLE, "doubleValue")); - map.put(char.class, Type.get(Character.class).getMethod(Type.CHAR, "charValue")); + map.put(boolean.class, TypeId.get(Boolean.class).getMethod(TypeId.BOOLEAN, "booleanValue")); + map.put(int.class, TypeId.get(Integer.class).getMethod(TypeId.INT, "intValue")); + map.put(byte.class, TypeId.get(Byte.class).getMethod(TypeId.BYTE, "byteValue")); + map.put(long.class, TypeId.get(Long.class).getMethod(TypeId.LONG, "longValue")); + map.put(short.class, TypeId.get(Short.class).getMethod(TypeId.SHORT, "shortValue")); + map.put(float.class, TypeId.get(Float.class).getMethod(TypeId.FLOAT, "floatValue")); + map.put(double.class, TypeId.get(Double.class).getMethod(TypeId.DOUBLE, "doubleValue")); + map.put(char.class, TypeId.get(Character.class).getMethod(TypeId.CHAR, "charValue")); PRIMITIVE_TO_UNBOX_METHOD = map; } diff --git a/src/test/java/com/google/dexmaker/DexMakerTest.java b/src/test/java/com/google/dexmaker/DexMakerTest.java index 719e692..6270c5f 100644 --- a/src/test/java/com/google/dexmaker/DexMakerTest.java +++ b/src/test/java/com/google/dexmaker/DexMakerTest.java @@ -40,15 +40,15 @@ import junit.framework.TestCase; */ public final class DexMakerTest extends TestCase { private DexMaker dexMaker; - private static Type<DexMakerTest> TEST_TYPE = Type.get(DexMakerTest.class); - private static Type<?> INT_ARRAY = Type.get(int[].class); - private static Type<boolean[]> BOOLEAN_ARRAY = Type.get(boolean[].class); - private static Type<long[]> LONG_ARRAY = Type.get(long[].class); - private static Type<Object[]> OBJECT_ARRAY = Type.get(Object[].class); - private static Type<long[][]> LONG_2D_ARRAY = Type.get(long[][].class); - private static Type<?> GENERATED = Type.get("LGenerated;"); - private static Type<Callable> CALLABLE = Type.get(Callable.class); - private static MethodId<Callable, Object> CALL = CALLABLE.getMethod(Type.OBJECT, "call"); + private static TypeId<DexMakerTest> TEST_TYPE = TypeId.get(DexMakerTest.class); + private static TypeId<?> INT_ARRAY = TypeId.get(int[].class); + private static TypeId<boolean[]> BOOLEAN_ARRAY = TypeId.get(boolean[].class); + private static TypeId<long[]> LONG_ARRAY = TypeId.get(long[].class); + private static TypeId<Object[]> OBJECT_ARRAY = TypeId.get(Object[].class); + private static TypeId<long[][]> LONG_2D_ARRAY = TypeId.get(long[][].class); + private static TypeId<?> GENERATED = TypeId.get("LGenerated;"); + private static TypeId<Callable> CALLABLE = TypeId.get(Callable.class); + private static MethodId<Callable, Object> CALL = CALLABLE.getMethod(TypeId.OBJECT, "call"); @Override protected void setUp() throws Exception { super.setUp(); @@ -61,7 +61,7 @@ public final class DexMakerTest extends TestCase { */ private void reset() { dexMaker = new DexMaker(); - dexMaker.declare(GENERATED, "Generated.java", PUBLIC, Type.OBJECT); + dexMaker.declare(GENERATED, "Generated.java", PUBLIC, TypeId.OBJECT); } public void testNewInstance() throws Exception { @@ -71,14 +71,14 @@ public final class DexMakerTest extends TestCase { * return result; * } */ - Type<Constructable> constructable = Type.get(Constructable.class); + TypeId<Constructable> constructable = TypeId.get(Constructable.class); MethodId<?, Constructable> methodId = GENERATED.getMethod( - constructable, "call", Type.LONG, Type.BOOLEAN); + constructable, "call", TypeId.LONG, TypeId.BOOLEAN); Code code = dexMaker.declare(methodId, PUBLIC | STATIC); - Local<Long> localA = code.getParameter(0, Type.LONG); - Local<Boolean> localB = code.getParameter(1, Type.BOOLEAN); + Local<Long> localA = code.getParameter(0, TypeId.LONG); + Local<Boolean> localB = code.getParameter(1, TypeId.BOOLEAN); MethodId<Constructable, Void> constructor - = constructable.getConstructor(Type.LONG, Type.BOOLEAN); + = constructable.getConstructor(TypeId.LONG, TypeId.BOOLEAN); Local<Constructable> localResult = code.newLocal(constructable); code.newInstance(localResult, constructor, localA, localB); code.returnValue(localResult); @@ -102,7 +102,7 @@ public final class DexMakerTest extends TestCase { * public void call() { * } */ - MethodId<?, Void> methodId = GENERATED.getMethod(Type.VOID, "call"); + MethodId<?, Void> methodId = GENERATED.getMethod(TypeId.VOID, "call"); Code code = dexMaker.declare(methodId, PUBLIC); code.returnVoid(); @@ -121,12 +121,12 @@ public final class DexMakerTest extends TestCase { * return result; * } */ - MethodId<?, Integer> methodId = GENERATED.getMethod(Type.INT, "call", Type.INT); + MethodId<?, Integer> methodId = GENERATED.getMethod(TypeId.INT, "call", TypeId.INT); Code code = dexMaker.declare(methodId, PUBLIC | STATIC); - Local<Integer> localA = code.getParameter(0, Type.INT); - Local<Integer> localResult = code.newLocal(Type.INT); + Local<Integer> localA = code.getParameter(0, TypeId.INT); + Local<Integer> localResult = code.newLocal(TypeId.INT); MethodId<?, Integer> staticMethod - = TEST_TYPE.getMethod(Type.INT, "staticMethod", Type.INT); + = TEST_TYPE.getMethod(TypeId.INT, "staticMethod", TypeId.INT); code.invokeStatic(staticMethod, localResult, localA); code.returnValue(localResult); @@ -139,8 +139,8 @@ public final class DexMakerTest extends TestCase { * Method method = null; * } */ - MethodId<?, Void> methodId = GENERATED.getMethod(Type.VOID, "call", Type.INT); - Type<Method> methodType = Type.get(Method.class); + MethodId<?, Void> methodId = GENERATED.getMethod(TypeId.VOID, "call", TypeId.INT); + TypeId<Method> methodType = TypeId.get(Method.class); Code code = dexMaker.declare(methodId, PUBLIC); Local<Method> localMethod = code.newLocal(methodType); code.loadConstant(localMethod, null); @@ -166,13 +166,13 @@ public final class DexMakerTest extends TestCase { * return result; * } */ - MethodId<?, Integer> methodId = GENERATED.getMethod(Type.INT, "call", TEST_TYPE, Type.INT); + MethodId<?, Integer> methodId = GENERATED.getMethod(TypeId.INT, "call", TEST_TYPE, TypeId.INT); Code code = dexMaker.declare(methodId, PUBLIC | STATIC); Local<DexMakerTest> localInstance = code.getParameter(0, TEST_TYPE); - Local<Integer> localA = code.getParameter(1, Type.INT); - Local<Integer> localResult = code.newLocal(Type.INT); + Local<Integer> localA = code.getParameter(1, TypeId.INT); + Local<Integer> localResult = code.newLocal(TypeId.INT); MethodId<DexMakerTest, Integer> virtualMethod - = TEST_TYPE.getMethod(Type.INT, "virtualMethod", Type.INT); + = TEST_TYPE.getMethod(TypeId.INT, "virtualMethod", TypeId.INT); code.invokeVirtual(virtualMethod, localResult, localInstance, localA); code.returnValue(localResult); @@ -196,17 +196,17 @@ public final class DexMakerTest extends TestCase { * return b; * } */ - Type<G> generated = Type.get("LGenerated;"); - MethodId<G, Integer> directMethodId = generated.getMethod(Type.INT, "directMethod"); + TypeId<G> generated = TypeId.get("LGenerated;"); + MethodId<G, Integer> directMethodId = generated.getMethod(TypeId.INT, "directMethod"); Code directCode = dexMaker.declare(directMethodId, PRIVATE); directCode.getThis(generated); // 'this' is unused - Local<Integer> localA = directCode.newLocal(Type.INT); + Local<Integer> localA = directCode.newLocal(TypeId.INT); directCode.loadConstant(localA, 5); directCode.returnValue(localA); - MethodId<G, Integer> methodId = generated.getMethod(Type.INT, "call", generated); + MethodId<G, Integer> methodId = generated.getMethod(TypeId.INT, "call", generated); Code code = dexMaker.declare(methodId, PUBLIC | STATIC); - Local<Integer> localB = code.newLocal(Type.INT); + Local<Integer> localB = code.newLocal(TypeId.INT); Local<G> localG = code.getParameter(0, generated); code.invokeDirect(directMethodId, localB, localG); code.returnValue(localB); @@ -229,18 +229,18 @@ public final class DexMakerTest extends TestCase { * return 0; * } */ - Type<G> generated = Type.get("LGenerated;"); - MethodId<Object, Integer> objectHashCode = Type.OBJECT.getMethod(Type.INT, "hashCode"); + TypeId<G> generated = TypeId.get("LGenerated;"); + MethodId<Object, Integer> objectHashCode = TypeId.OBJECT.getMethod(TypeId.INT, "hashCode"); Code superHashCode = dexMaker.declare( - GENERATED.getMethod(Type.INT, "superHashCode"), PUBLIC); - Local<Integer> localResult = superHashCode.newLocal(Type.INT); + GENERATED.getMethod(TypeId.INT, "superHashCode"), PUBLIC); + Local<Integer> localResult = superHashCode.newLocal(TypeId.INT); Local<G> localThis = superHashCode.getThis(generated); superHashCode.invokeSuper(objectHashCode, localResult, localThis); superHashCode.returnValue(localResult); Code generatedHashCode = dexMaker.declare( - GENERATED.getMethod(Type.INT, "hashCode"), PUBLIC); - Local<Integer> localZero = generatedHashCode.newLocal(Type.INT); + GENERATED.getMethod(TypeId.INT, "hashCode"), PUBLIC); + Local<Integer> localZero = generatedHashCode.newLocal(TypeId.INT); generatedHashCode.loadConstant(localZero, 0); generatedHashCode.returnValue(localZero); @@ -259,10 +259,10 @@ public final class DexMakerTest extends TestCase { * return result; * } */ - MethodId<?, Object> methodId = GENERATED.getMethod(Type.OBJECT, "call", CALLABLE); + MethodId<?, Object> methodId = GENERATED.getMethod(TypeId.OBJECT, "call", CALLABLE); Code code = dexMaker.declare(methodId, PUBLIC | STATIC); Local<Callable> localC = code.getParameter(0, CALLABLE); - Local<Object> localResult = code.newLocal(Type.OBJECT); + Local<Object> localResult = code.newLocal(TypeId.OBJECT); code.invokeInterface(CALL, localResult, localC); code.returnValue(localResult); @@ -275,18 +275,18 @@ public final class DexMakerTest extends TestCase { } public void testParameterMismatch() throws Exception { - Type<?>[] argTypes = { - Type.get(Integer.class), // should fail because the code specifies int - Type.OBJECT, + TypeId<?>[] argTypes = { + TypeId.get(Integer.class), // should fail because the code specifies int + TypeId.OBJECT, }; - MethodId<?, Integer> methodId = GENERATED.getMethod(Type.INT, "call", argTypes); + MethodId<?, Integer> methodId = GENERATED.getMethod(TypeId.INT, "call", argTypes); Code code = dexMaker.declare(methodId, PUBLIC | STATIC); try { - code.getParameter(0, Type.INT); + code.getParameter(0, TypeId.INT); } catch (IllegalArgumentException e) { } try { - code.getParameter(2, Type.INT); + code.getParameter(2, TypeId.INT); } catch (IndexOutOfBoundsException e) { } } @@ -299,15 +299,16 @@ public final class DexMakerTest extends TestCase { * return result; * } */ - MethodId<?, Boolean> methodId = GENERATED.getMethod(Type.BOOLEAN, "call", TEST_TYPE); + MethodId<?, Boolean> methodId = GENERATED.getMethod(TypeId.BOOLEAN, "call", TEST_TYPE); Code code = dexMaker.declare(methodId, PUBLIC | STATIC); Local<DexMakerTest> localTest = code.getParameter(0, TEST_TYPE); - Type<CharSequence> charSequenceType = Type.get(CharSequence.class); - MethodId<Object, String> objectToString = Type.OBJECT.getMethod(Type.STRING, "toString"); + TypeId<CharSequence> charSequenceType = TypeId.get(CharSequence.class); + MethodId<Object, String> objectToString + = TypeId.OBJECT.getMethod(TypeId.STRING, "toString"); MethodId<Object, Boolean> objectEquals - = Type.OBJECT.getMethod(Type.BOOLEAN, "equals", Type.OBJECT); + = TypeId.OBJECT.getMethod(TypeId.BOOLEAN, "equals", TypeId.OBJECT); Local<CharSequence> localCs = code.newLocal(charSequenceType); - Local<Boolean> localResult = code.newLocal(Type.BOOLEAN); + Local<Boolean> localResult = code.newLocal(TypeId.BOOLEAN); code.invokeVirtual(objectToString, localCs, localTest); code.invokeVirtual(objectEquals, localResult, localCs, localTest); code.returnValue(localResult); @@ -316,10 +317,10 @@ public final class DexMakerTest extends TestCase { } public void testReturnTypeMismatch() { - MethodId<?, String> methodId = GENERATED.getMethod(Type.STRING, "call"); + MethodId<?, String> methodId = GENERATED.getMethod(TypeId.STRING, "call"); Code code = dexMaker.declare(methodId, PUBLIC | STATIC); try { - code.returnValue(code.newLocal(Type.BOOLEAN)); + code.returnValue(code.newLocal(TypeId.BOOLEAN)); fail(); } catch (IllegalArgumentException expected) { } @@ -337,8 +338,8 @@ public final class DexMakerTest extends TestCase { * protected static Object b; * } */ - dexMaker.declare(GENERATED.getField(Type.INT, "a"), PUBLIC | STATIC, 3); - dexMaker.declare(GENERATED.getField(Type.OBJECT, "b"), PROTECTED | STATIC, null); + dexMaker.declare(GENERATED.getField(TypeId.INT, "a"), PUBLIC | STATIC, 3); + dexMaker.declare(GENERATED.getField(TypeId.OBJECT, "b"), PROTECTED | STATIC, null); Class<?> generatedClass = generateAndLoad(); Field a = generatedClass.getField("a"); @@ -358,8 +359,8 @@ public final class DexMakerTest extends TestCase { * protected Object b; * } */ - dexMaker.declare(GENERATED.getField(Type.INT, "a"), PUBLIC, null); - dexMaker.declare(GENERATED.getField(Type.OBJECT, "b"), PROTECTED, null); + dexMaker.declare(GENERATED.getField(TypeId.INT, "a"), PUBLIC, null); + dexMaker.declare(GENERATED.getField(TypeId.OBJECT, "b"), PROTECTED, null); addDefaultConstructor(); @@ -389,14 +390,14 @@ public final class DexMakerTest extends TestCase { * } * } */ - Type<G> generated = Type.get("LGenerated;"); - FieldId<G, Integer> fieldId = generated.getField(Type.INT, "a"); + TypeId<G> generated = TypeId.get("LGenerated;"); + FieldId<G, Integer> fieldId = generated.getField(TypeId.INT, "a"); dexMaker.declare(fieldId, PUBLIC | FINAL, null); - MethodId<?, Void> constructor = GENERATED.getConstructor(Type.INT); + MethodId<?, Void> constructor = GENERATED.getConstructor(TypeId.INT); Code code = dexMaker.declareConstructor(constructor, PUBLIC); Local<G> thisRef = code.getThis(generated); - Local<Integer> parameter = code.getParameter(0, Type.INT); - code.invokeDirect(Type.OBJECT.getConstructor(), null, thisRef); + Local<Integer> parameter = code.getParameter(0, TypeId.INT); + code.invokeDirect(TypeId.OBJECT.getConstructor(), null, thisRef); code.iput(fieldId, thisRef, parameter); code.returnVoid(); @@ -428,7 +429,7 @@ public final class DexMakerTest extends TestCase { * } */ reset(); - Type<T> returnType = Type.get(javaType); + TypeId<T> returnType = TypeId.get(javaType); Code code = dexMaker.declare(GENERATED.getMethod(returnType, "call"), PUBLIC | STATIC); if (value != null) { Local<T> i = code.newLocal(returnType); @@ -487,14 +488,14 @@ public final class DexMakerTest extends TestCase { */ reset(); MethodId<?, Boolean> methodId = GENERATED.getMethod( - Type.BOOLEAN, "call", Type.INT, Type.INT); + TypeId.BOOLEAN, "call", TypeId.INT, TypeId.INT); Code code = dexMaker.declare(methodId, PUBLIC | STATIC); - Local<Integer> localA = code.getParameter(0, Type.INT); - Local<Integer> localB = code.getParameter(1, Type.INT); - Local<Boolean> result = code.newLocal(Type.get(boolean.class)); + Local<Integer> localA = code.getParameter(0, TypeId.INT); + Local<Integer> localB = code.getParameter(1, TypeId.INT); + Local<Boolean> result = code.newLocal(TypeId.get(boolean.class)); Label afterIf = code.newLabel(); Label ifBody = code.newLabel(); - code.compare(comparison, localA, localB, ifBody); + code.compare(comparison, ifBody, localA, localB); code.jump(afterIf); code.mark(ifBody); @@ -620,13 +621,13 @@ public final class DexMakerTest extends TestCase { * } */ reset(); - Type<?> sourceType = Type.get(source); - Type<?> targetType = Type.get(target); + TypeId<?> sourceType = TypeId.get(source); + TypeId<?> targetType = TypeId.get(target); MethodId<?, ?> methodId = GENERATED.getMethod(targetType, "call", sourceType); Code code = dexMaker.declare(methodId, PUBLIC | STATIC); Local<?> localSource = code.getParameter(0, sourceType); Local<?> localCasted = code.newLocal(targetType); - code.numericCast(localSource, localCasted); + code.numericCast(localCasted, localSource); code.returnValue(localCasted); return getMethod(); } @@ -651,7 +652,7 @@ public final class DexMakerTest extends TestCase { * } */ reset(); - Type<T> valueType = Type.get(source); + TypeId<T> valueType = TypeId.get(source); MethodId<?, T> methodId = GENERATED.getMethod(valueType, "call", valueType); Code code = dexMaker.declare(methodId, PUBLIC | STATIC); Local<T> localSource = code.getParameter(0, valueType); @@ -692,7 +693,7 @@ public final class DexMakerTest extends TestCase { * } */ reset(); - Type<T> valueType = Type.get(source); + TypeId<T> valueType = TypeId.get(source); MethodId<?, T> methodId = GENERATED.getMethod(valueType, "call", valueType); Code code = dexMaker.declare(methodId, PUBLIC | STATIC); Local<T> localSource = code.getParameter(0, valueType); @@ -847,7 +848,7 @@ public final class DexMakerTest extends TestCase { * } */ reset(); - Type<T> valueType = Type.get(valueClass); + TypeId<T> valueType = TypeId.get(valueClass); MethodId<?, T> methodId = GENERATED.getMethod(valueType, "call", valueType, valueType); Code code = dexMaker.declare(methodId, PUBLIC | STATIC); Local<T> localA = code.getParameter(0, valueType); @@ -929,15 +930,15 @@ public final class DexMakerTest extends TestCase { * } */ reset(); - Type<V> valueType = Type.get(valueClass); - Type<Instance> objectType = Type.get(Instance.class); + TypeId<V> valueType = TypeId.get(valueClass); + TypeId<Instance> objectType = TypeId.get(Instance.class); FieldId<Instance, V> fieldId = objectType.getField(valueType, fieldName); MethodId<?, V> methodId = GENERATED.getMethod(valueType, "call", objectType, valueType); Code code = dexMaker.declare(methodId, PUBLIC | STATIC); Local<Instance> localInstance = code.getParameter(0, objectType); Local<V> localNewValue = code.getParameter(1, valueType); Local<V> localOldValue = code.newLocal(valueType); - code.iget(fieldId, localInstance, localOldValue); + code.iget(fieldId, localOldValue, localInstance); code.iput(fieldId, localInstance, localNewValue); code.returnValue(localOldValue); return getMethod(); @@ -1012,8 +1013,8 @@ public final class DexMakerTest extends TestCase { * } */ reset(); - Type<V> valueType = Type.get(valueClass); - Type<Static> objectType = Type.get(Static.class); + TypeId<V> valueType = TypeId.get(valueClass); + TypeId<Static> objectType = TypeId.get(Static.class); FieldId<Static, V> fieldId = objectType.getField(valueType, fieldName); MethodId<?, V> methodId = GENERATED.getMethod(valueType, "call", valueType); Code code = dexMaker.declare(methodId, PUBLIC | STATIC); @@ -1031,11 +1032,11 @@ public final class DexMakerTest extends TestCase { * String s = (String) o; * } */ - MethodId<?, String> methodId = GENERATED.getMethod(Type.STRING, "call", Type.OBJECT); + MethodId<?, String> methodId = GENERATED.getMethod(TypeId.STRING, "call", TypeId.OBJECT); Code code = dexMaker.declare(methodId, PUBLIC | STATIC); - Local<Object> localObject = code.getParameter(0, Type.OBJECT); - Local<String> localString = code.newLocal(Type.STRING); - code.typeCast(localObject, localString); + Local<Object> localObject = code.getParameter(0, TypeId.OBJECT); + Local<String> localString = code.newLocal(TypeId.STRING); + code.typeCast(localString, localObject); code.returnValue(localString); Method method = getMethod(); @@ -1056,11 +1057,11 @@ public final class DexMakerTest extends TestCase { * return result; * } */ - MethodId<?, Boolean> methodId = GENERATED.getMethod(Type.BOOLEAN, "call", Type.OBJECT); + MethodId<?, Boolean> methodId = GENERATED.getMethod(TypeId.BOOLEAN, "call", TypeId.OBJECT); Code code = dexMaker.declare(methodId, PUBLIC | STATIC); - Local<Object> localObject = code.getParameter(0, Type.OBJECT); - Local<Boolean> localResult = code.newLocal(Type.BOOLEAN); - code.instanceOfType(localResult, localObject, Type.STRING); + Local<Object> localObject = code.getParameter(0, TypeId.OBJECT); + Local<Boolean> localResult = code.newLocal(TypeId.BOOLEAN); + code.instanceOfType(localResult, localObject, TypeId.STRING); code.returnValue(localResult); Method method = getMethod(); @@ -1082,13 +1083,13 @@ public final class DexMakerTest extends TestCase { * return result; * } */ - MethodId<?, Integer> methodId = GENERATED.getMethod(Type.INT, "call", Type.INT); + MethodId<?, Integer> methodId = GENERATED.getMethod(TypeId.INT, "call", TypeId.INT); Code code = dexMaker.declare(methodId, PUBLIC | STATIC); - Local<Integer> localCount = code.getParameter(0, Type.INT); - Local<Integer> localResult = code.newLocal(Type.INT); - Local<Integer> localI = code.newLocal(Type.INT); - Local<Integer> local1 = code.newLocal(Type.INT); - Local<Integer> local2 = code.newLocal(Type.INT); + Local<Integer> localCount = code.getParameter(0, TypeId.INT); + Local<Integer> localResult = code.newLocal(TypeId.INT); + Local<Integer> localI = code.newLocal(TypeId.INT); + Local<Integer> local1 = code.newLocal(TypeId.INT); + Local<Integer> local2 = code.newLocal(TypeId.INT); code.loadConstant(local1, 1); code.loadConstant(local2, 2); code.loadConstant(localResult, 1); @@ -1097,7 +1098,7 @@ public final class DexMakerTest extends TestCase { Label loopBody = code.newLabel(); Label afterLoop = code.newLabel(); code.mark(loopCondition); - code.compare(Comparison.LT, localI, localCount, loopBody); + code.compare(Comparison.LT, loopBody, localI, localCount); code.jump(afterLoop); code.mark(loopBody); code.op(BinaryOp.MULTIPLY, localResult, localResult, local2); @@ -1127,18 +1128,18 @@ public final class DexMakerTest extends TestCase { * return result; * } */ - MethodId<?, Integer> methodId = GENERATED.getMethod(Type.INT, "call", Type.INT); + MethodId<?, Integer> methodId = GENERATED.getMethod(TypeId.INT, "call", TypeId.INT); Code code = dexMaker.declare(methodId, PUBLIC | STATIC); - Local<Integer> localMax = code.getParameter(0, Type.INT); - Local<Integer> localResult = code.newLocal(Type.INT); - Local<Integer> local2 = code.newLocal(Type.INT); + Local<Integer> localMax = code.getParameter(0, TypeId.INT); + Local<Integer> localResult = code.newLocal(TypeId.INT); + Local<Integer> local2 = code.newLocal(TypeId.INT); code.loadConstant(localResult, 1); code.loadConstant(local2, 2); Label loopCondition = code.newLabel(); Label loopBody = code.newLabel(); Label afterLoop = code.newLabel(); code.mark(loopCondition); - code.compare(Comparison.LT, localResult, localMax, loopBody); + code.compare(Comparison.LT, loopBody, localResult, localMax); code.jump(afterLoop); code.mark(loopBody); code.op(BinaryOp.MULTIPLY, localResult, localResult, local2); @@ -1172,20 +1173,20 @@ public final class DexMakerTest extends TestCase { * } */ MethodId<?, Integer> methodId = GENERATED.getMethod( - Type.INT, "call", Type.INT, Type.INT, Type.INT); + TypeId.INT, "call", TypeId.INT, TypeId.INT, TypeId.INT); Code code = dexMaker.declare(methodId, PUBLIC | STATIC); - Local<Integer> localA = code.getParameter(0, Type.INT); - Local<Integer> localB = code.getParameter(1, Type.INT); - Local<Integer> localC = code.getParameter(2, Type.INT); + Local<Integer> localA = code.getParameter(0, TypeId.INT); + Local<Integer> localB = code.getParameter(1, TypeId.INT); + Local<Integer> localC = code.getParameter(2, TypeId.INT); Label aLessThanB = code.newLabel(); Label aLessThanC = code.newLabel(); Label bLessThanC = code.newLabel(); - code.compare(Comparison.LT, localA, localB, aLessThanB); - code.compare(Comparison.LT, localB, localC, bLessThanC); + code.compare(Comparison.LT, aLessThanB, localA, localB); + code.compare(Comparison.LT, bLessThanC, localB, localC); code.returnValue(localC); // (a < b) code.mark(aLessThanB); - code.compare(Comparison.LT, localA, localC, aLessThanC); + code.compare(Comparison.LT, aLessThanC, localA, localC); code.returnValue(localC); // (a < c) code.mark(aLessThanC); @@ -1215,18 +1216,18 @@ public final class DexMakerTest extends TestCase { * return result; * } */ - MethodId<?, Integer> methodId = GENERATED.getMethod(Type.INT, "call", Type.INT); + MethodId<?, Integer> methodId = GENERATED.getMethod(TypeId.INT, "call", TypeId.INT); Code code = dexMaker.declare(methodId, PUBLIC | STATIC); - Local<Integer> localA = code.getParameter(0, Type.INT); - Local<Integer> local1 = code.newLocal(Type.INT); - Local<Integer> local2 = code.newLocal(Type.INT); - Local<Integer> localX = code.newLocal(Type.INT); - Local<Integer> localY = code.newLocal(Type.INT); - Local<Integer> localResult = code.newLocal(Type.INT); + Local<Integer> localA = code.getParameter(0, TypeId.INT); + Local<Integer> local1 = code.newLocal(TypeId.INT); + Local<Integer> local2 = code.newLocal(TypeId.INT); + Local<Integer> localX = code.newLocal(TypeId.INT); + Local<Integer> localY = code.newLocal(TypeId.INT); + Local<Integer> localResult = code.newLocal(TypeId.INT); Label baseCase = code.newLabel(); code.loadConstant(local1, 1); code.loadConstant(local2, 2); - code.compare(Comparison.LT, localA, local2, baseCase); + code.compare(Comparison.LT, baseCase, localA, local2); code.op(BinaryOp.SUBTRACT, localA, localA, local1); code.invokeStatic(methodId, localX, localA); code.op(BinaryOp.SUBTRACT, localA, localA, local1); @@ -1260,18 +1261,18 @@ public final class DexMakerTest extends TestCase { * return "RE"; * } */ - MethodId<?, String> methodId = GENERATED.getMethod(Type.STRING, "call", Type.INT); + MethodId<?, String> methodId = GENERATED.getMethod(TypeId.STRING, "call", TypeId.INT); Code code = dexMaker.declare(methodId, PUBLIC | STATIC); - Local<Integer> localI = code.getParameter(0, Type.INT); - Local<String> result = code.newLocal(Type.STRING); + Local<Integer> localI = code.getParameter(0, TypeId.INT); + Local<String> result = code.newLocal(TypeId.STRING); Label catchIae = code.newLabel(); Label catchIse = code.newLabel(); Label catchRe = code.newLabel(); - code.addCatchClause(Type.get(IllegalArgumentException.class), catchIae); - code.addCatchClause(Type.get(IllegalStateException.class), catchIse); - code.addCatchClause(Type.get(RuntimeException.class), catchRe); - MethodId<?, ?> thrower = TEST_TYPE.getMethod(Type.VOID, "thrower", Type.INT); + code.addCatchClause(TypeId.get(IllegalArgumentException.class), catchIae); + code.addCatchClause(TypeId.get(IllegalStateException.class), catchIse); + code.addCatchClause(TypeId.get(RuntimeException.class), catchRe); + MethodId<?, ?> thrower = TEST_TYPE.getMethod(TypeId.VOID, "thrower", TypeId.INT); code.invokeStatic(thrower, null, localI); code.loadConstant(result, "NONE"); code.returnValue(result); @@ -1336,19 +1337,19 @@ public final class DexMakerTest extends TestCase { * } */ MethodId<?, String> methodId = GENERATED.getMethod( - Type.STRING, "call", Type.INT, Type.INT, Type.INT); + TypeId.STRING, "call", TypeId.INT, TypeId.INT, TypeId.INT); Code code = dexMaker.declare(methodId, PUBLIC | STATIC); - Local<Integer> localA = code.getParameter(0, Type.INT); - Local<Integer> localB = code.getParameter(1, Type.INT); - Local<Integer> localC = code.getParameter(2, Type.INT); - Local<String> localResult = code.newLocal(Type.STRING); + Local<Integer> localA = code.getParameter(0, TypeId.INT); + Local<Integer> localB = code.getParameter(1, TypeId.INT); + Local<Integer> localC = code.getParameter(2, TypeId.INT); + Local<String> localResult = code.newLocal(TypeId.STRING); Label catchInner = code.newLabel(); Label catchOuter = code.newLabel(); - Type<IllegalArgumentException> iaeType = Type.get(IllegalArgumentException.class); + TypeId<IllegalArgumentException> iaeType = TypeId.get(IllegalArgumentException.class); code.addCatchClause(iaeType, catchOuter); - MethodId<?, ?> thrower = TEST_TYPE.getMethod(Type.VOID, "thrower", Type.INT); + MethodId<?, ?> thrower = TEST_TYPE.getMethod(TypeId.VOID, "thrower", TypeId.INT); code.invokeStatic(thrower, null, localA); // for the inner catch clause, we stash the old label and put it back afterwards. @@ -1382,9 +1383,9 @@ public final class DexMakerTest extends TestCase { * throw new IllegalStateException(); * } */ - MethodId<?, Void> methodId = GENERATED.getMethod(Type.VOID, "call"); + MethodId<?, Void> methodId = GENERATED.getMethod(TypeId.VOID, "call"); Code code = dexMaker.declare(methodId, PUBLIC | STATIC); - Type<IllegalStateException> iseType = Type.get(IllegalStateException.class); + TypeId<IllegalStateException> iseType = TypeId.get(IllegalStateException.class); MethodId<IllegalStateException, Void> iseConstructor = iseType.getConstructor(); Local<IllegalStateException> localIse = code.newLocal(iseType); code.newInstance(localIse, iseConstructor); @@ -1403,14 +1404,14 @@ public final class DexMakerTest extends TestCase { * public static void call(int unused1, long unused2, long unused3) {} */ MethodId<?, Void> methodId = GENERATED.getMethod( - Type.VOID, "call", Type.INT, Type.LONG, Type.LONG); + TypeId.VOID, "call", TypeId.INT, TypeId.LONG, TypeId.LONG); Code code = dexMaker.declare(methodId, PUBLIC | STATIC); code.returnVoid(); getMethod().invoke(null, 1, 2, 3); } public void testFloatingPointCompare() throws Exception { - Method floatG = floatingPointCompareMethod(Type.FLOAT, 1); + Method floatG = floatingPointCompareMethod(TypeId.FLOAT, 1); assertEquals(-1, floatG.invoke(null, 1.0f, Float.POSITIVE_INFINITY)); assertEquals(-1, floatG.invoke(null, 1.0f, 2.0f)); assertEquals(0, floatG.invoke(null, 1.0f, 1.0f)); @@ -1420,7 +1421,7 @@ public final class DexMakerTest extends TestCase { assertEquals(1, floatG.invoke(null, Float.NaN, Float.NaN)); assertEquals(1, floatG.invoke(null, Float.NaN, Float.POSITIVE_INFINITY)); - Method floatL = floatingPointCompareMethod(Type.FLOAT, -1); + Method floatL = floatingPointCompareMethod(TypeId.FLOAT, -1); assertEquals(-1, floatG.invoke(null, 1.0f, Float.POSITIVE_INFINITY)); assertEquals(-1, floatL.invoke(null, 1.0f, 2.0f)); assertEquals(0, floatL.invoke(null, 1.0f, 1.0f)); @@ -1430,7 +1431,7 @@ public final class DexMakerTest extends TestCase { assertEquals(-1, floatL.invoke(null, Float.NaN, Float.NaN)); assertEquals(-1, floatL.invoke(null, Float.NaN, Float.POSITIVE_INFINITY)); - Method doubleG = floatingPointCompareMethod(Type.DOUBLE, 1); + Method doubleG = floatingPointCompareMethod(TypeId.DOUBLE, 1); assertEquals(-1, doubleG.invoke(null, 1.0, Double.POSITIVE_INFINITY)); assertEquals(-1, doubleG.invoke(null, 1.0, 2.0)); assertEquals(0, doubleG.invoke(null, 1.0, 1.0)); @@ -1440,7 +1441,7 @@ public final class DexMakerTest extends TestCase { assertEquals(1, doubleG.invoke(null, Double.NaN, Double.NaN)); assertEquals(1, doubleG.invoke(null, Double.NaN, Double.POSITIVE_INFINITY)); - Method doubleL = floatingPointCompareMethod(Type.DOUBLE, -1); + Method doubleL = floatingPointCompareMethod(TypeId.DOUBLE, -1); assertEquals(-1, doubleL.invoke(null, 1.0, Double.POSITIVE_INFINITY)); assertEquals(-1, doubleL.invoke(null, 1.0, 2.0)); assertEquals(0, doubleL.invoke(null, 1.0, 1.0)); @@ -1452,7 +1453,7 @@ public final class DexMakerTest extends TestCase { } private <T extends Number> Method floatingPointCompareMethod( - Type<T> valueType, int nanValue) throws Exception { + TypeId<T> valueType, int nanValue) throws Exception { /* * public static int call(float a, float b) { * int result = a <=> b; @@ -1460,12 +1461,13 @@ public final class DexMakerTest extends TestCase { * } */ reset(); - MethodId<?, Integer> methodId = GENERATED.getMethod(Type.INT, "call", valueType, valueType); + MethodId<?, Integer> methodId = GENERATED.getMethod( + TypeId.INT, "call", valueType, valueType); Code code = dexMaker.declare(methodId, PUBLIC | STATIC); Local<T> localA = code.getParameter(0, valueType); Local<T> localB = code.getParameter(1, valueType); - Local<Integer> localResult = code.newLocal(Type.INT); - code.compare(localA, localB, localResult, nanValue); + Local<Integer> localResult = code.newLocal(TypeId.INT); + code.compare(localResult, localA, localB, nanValue); code.returnValue(localResult); return getMethod(); } @@ -1477,12 +1479,12 @@ public final class DexMakerTest extends TestCase { * return result; * } */ - MethodId<?, Integer> methodId = GENERATED.getMethod(Type.INT, "call", Type.LONG, Type.LONG); + MethodId<?, Integer> methodId = GENERATED.getMethod(TypeId.INT, "call", TypeId.LONG, TypeId.LONG); Code code = dexMaker.declare(methodId, PUBLIC | STATIC); - Local<Long> localA = code.getParameter(0, Type.LONG); - Local<Long> localB = code.getParameter(1, Type.LONG); - Local<Integer> localResult = code.newLocal(Type.INT); - code.compare(localA, localB, localResult); + Local<Long> localA = code.getParameter(0, TypeId.LONG); + Local<Long> localB = code.getParameter(1, TypeId.LONG); + Local<Integer> localResult = code.newLocal(TypeId.INT); + code.compare(localResult, localA, localB); code.returnValue(localResult); Method method = getMethod(); @@ -1519,7 +1521,7 @@ public final class DexMakerTest extends TestCase { assertEquals(5, long2dArrayLength.invoke(null, new Object[] { new long[5][10] })); } - private <T> Method arrayLengthMethod(Type<T> valueType) throws Exception { + private <T> Method arrayLengthMethod(TypeId<T> valueType) throws Exception { /* * public static int call(long[] array) { * int result = array.length; @@ -1527,11 +1529,11 @@ public final class DexMakerTest extends TestCase { * } */ reset(); - MethodId<?, Integer> methodId = GENERATED.getMethod(Type.INT, "call", valueType); + MethodId<?, Integer> methodId = GENERATED.getMethod(TypeId.INT, "call", valueType); Code code = dexMaker.declare(methodId, PUBLIC | STATIC); Local<T> localArray = code.getParameter(0, valueType); - Local<Integer> localResult = code.newLocal(Type.INT); - code.arrayLength(localArray, localResult); + Local<Integer> localResult = code.newLocal(TypeId.INT); + code.arrayLength(localResult, localArray); code.returnValue(localResult); return getMethod(); } @@ -1561,7 +1563,7 @@ public final class DexMakerTest extends TestCase { Arrays.deepToString((long[][]) new2dLongArray.invoke(null, 3))); } - private <T> Method newArrayMethod(Type<T> valueType) throws Exception { + private <T> Method newArrayMethod(TypeId<T> valueType) throws Exception { /* * public static long[] call(int length) { * long[] result = new long[length]; @@ -1569,32 +1571,32 @@ public final class DexMakerTest extends TestCase { * } */ reset(); - MethodId<?, T> methodId = GENERATED.getMethod(valueType, "call", Type.INT); + MethodId<?, T> methodId = GENERATED.getMethod(valueType, "call", TypeId.INT); Code code = dexMaker.declare(methodId, PUBLIC | STATIC); - Local<Integer> localLength = code.getParameter(0, Type.INT); + Local<Integer> localLength = code.getParameter(0, TypeId.INT); Local<T> localResult = code.newLocal(valueType); - code.newArray(localLength, localResult); + code.newArray(localResult, localLength); code.returnValue(localResult); return getMethod(); } public void testReadAndWriteArray() throws Exception { - Method swapBooleanArray = arraySwapMethod(BOOLEAN_ARRAY, Type.BOOLEAN); + Method swapBooleanArray = arraySwapMethod(BOOLEAN_ARRAY, TypeId.BOOLEAN); boolean[] booleans = new boolean[3]; assertEquals(false, swapBooleanArray.invoke(null, booleans, 1, true)); assertEquals("[false, true, false]", Arrays.toString(booleans)); - Method swapIntArray = arraySwapMethod(INT_ARRAY, Type.INT); + Method swapIntArray = arraySwapMethod(INT_ARRAY, TypeId.INT); int[] ints = new int[3]; assertEquals(0, swapIntArray.invoke(null, ints, 1, 5)); assertEquals("[0, 5, 0]", Arrays.toString(ints)); - Method swapLongArray = arraySwapMethod(LONG_ARRAY, Type.LONG); + Method swapLongArray = arraySwapMethod(LONG_ARRAY, TypeId.LONG); long[] longs = new long[3]; assertEquals(0L, swapLongArray.invoke(null, longs, 1, 6L)); assertEquals("[0, 6, 0]", Arrays.toString(longs)); - Method swapObjectArray = arraySwapMethod(OBJECT_ARRAY, Type.OBJECT); + Method swapObjectArray = arraySwapMethod(OBJECT_ARRAY, TypeId.OBJECT); Object[] objects = new Object[3]; assertEquals(null, swapObjectArray.invoke(null, objects, 1, "X")); assertEquals("[null, X, null]", Arrays.toString(objects)); @@ -1605,7 +1607,7 @@ public final class DexMakerTest extends TestCase { assertEquals("[null, [7], null]", Arrays.deepToString(longs2d)); } - private <A, T> Method arraySwapMethod(Type<A> arrayType, Type<T> singleType) + private <A, T> Method arraySwapMethod(TypeId<A> arrayType, TypeId<T> singleType) throws Exception { /* * public static long swap(long[] array, int index, long newValue) { @@ -1616,13 +1618,13 @@ public final class DexMakerTest extends TestCase { */ reset(); MethodId<?, T> methodId = GENERATED.getMethod( - singleType, "call", arrayType, Type.INT, singleType); + singleType, "call", arrayType, TypeId.INT, singleType); Code code = dexMaker.declare(methodId, PUBLIC | STATIC); Local<A> localArray = code.getParameter(0, arrayType); - Local<Integer> localIndex = code.getParameter(1, Type.INT); + Local<Integer> localIndex = code.getParameter(1, TypeId.INT); Local<T> localNewValue = code.getParameter(2, singleType); Local<T> localResult = code.newLocal(singleType); - code.aget(localArray, localIndex, localResult); + code.aget(localResult, localArray, localIndex); code.aput(localArray, localIndex, localNewValue); code.returnValue(localResult); return getMethod(); @@ -1634,10 +1636,14 @@ public final class DexMakerTest extends TestCase { // TODO: don't generate multiple times (?) + // TODO: array types + + // TODO: attempt to generate an interface + private void addDefaultConstructor() { Code code = dexMaker.declareConstructor(GENERATED.getConstructor(), PUBLIC); Local<?> thisRef = code.getThis(GENERATED); - code.invokeDirect(Type.OBJECT.getConstructor(), null, thisRef); + code.invokeDirect(TypeId.OBJECT.getConstructor(), null, thisRef); code.returnVoid(); } @@ -1662,7 +1668,7 @@ public final class DexMakerTest extends TestCase { } private Class<?> generateAndLoad() throws Exception { - return dexMaker.load(getClass().getClassLoader(), + return dexMaker.generateAndLoad(getClass().getClassLoader(), getDataDirectory(), getDataDirectory()).loadClass("Generated"); } } diff --git a/src/test/java/com/google/dexmaker/TypeTest.java b/src/test/java/com/google/dexmaker/TypeIdTest.java index 41da616..26e8413 100644 --- a/src/test/java/com/google/dexmaker/TypeTest.java +++ b/src/test/java/com/google/dexmaker/TypeIdTest.java @@ -18,13 +18,13 @@ package com.google.dexmaker; import junit.framework.TestCase; -public final class TypeTest extends TestCase { +public final class TypeIdTest extends TestCase { public void testGetType() { - assertEquals("Ljava/lang/String;", Type.get(String.class).getName()); - assertEquals("[Ljava/lang/String;", Type.get(String[].class).getName()); - assertEquals("[[Ljava/lang/String;", Type.get(String[][].class).getName()); - assertEquals("I", Type.get(int.class).getName()); - assertEquals("[I", Type.get(int[].class).getName()); - assertEquals("[[I", Type.get(int[][].class).getName()); + assertEquals("Ljava/lang/String;", TypeId.get(String.class).getName()); + assertEquals("[Ljava/lang/String;", TypeId.get(String[].class).getName()); + assertEquals("[[Ljava/lang/String;", TypeId.get(String[][].class).getName()); + assertEquals("I", TypeId.get(int.class).getName()); + assertEquals("[I", TypeId.get(int[].class).getName()); + assertEquals("[[I", TypeId.get(int[][].class).getName()); } } diff --git a/src/test/java/com/google/dexmaker/examples/FibonacciMaker.java b/src/test/java/com/google/dexmaker/examples/FibonacciMaker.java new file mode 100644 index 0000000..a7b220e --- /dev/null +++ b/src/test/java/com/google/dexmaker/examples/FibonacciMaker.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2012 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 com.google.dexmaker.examples; + +import com.google.dexmaker.BinaryOp; +import com.google.dexmaker.Code; +import com.google.dexmaker.Comparison; +import com.google.dexmaker.DexMaker; +import com.google.dexmaker.Label; +import com.google.dexmaker.Local; +import com.google.dexmaker.MethodId; +import com.google.dexmaker.TypeId; +import java.io.File; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +public final class FibonacciMaker { + public static void main(String[] args) throws Exception { + DexMaker dexMaker = new DexMaker(); + TypeId<?> fibonacci = TypeId.get("Lcom/google/dexmaker/examples/Fibonacci;"); + String fileName = "Fibonacci.generated"; + dexMaker.declare(fibonacci, fileName, Modifier.PUBLIC, TypeId.OBJECT); + + MethodId<?, Integer> fib = fibonacci.getMethod(TypeId.INT, "fib", TypeId.INT); + Code code = dexMaker.declare(fib, Modifier.PUBLIC | Modifier.STATIC); + Local<Integer> i = code.getParameter(0, TypeId.INT); + Local<Integer> constant1 = code.newLocal(TypeId.INT); + Local<Integer> constant2 = code.newLocal(TypeId.INT); + Local<Integer> a = code.newLocal(TypeId.INT); + Local<Integer> b = code.newLocal(TypeId.INT); + Local<Integer> c = code.newLocal(TypeId.INT); + Local<Integer> d = code.newLocal(TypeId.INT); + Local<Integer> result = code.newLocal(TypeId.INT); + code.loadConstant(constant1, 1); + code.loadConstant(constant2, 2); + Label baseCase = code.newLabel(); + code.compare(Comparison.LT, baseCase, i, constant2); + code.op(BinaryOp.SUBTRACT, a, i, constant1); + code.op(BinaryOp.SUBTRACT, b, i, constant2); + code.invokeStatic(fib, c, a); + code.invokeStatic(fib, d, b); + code.op(BinaryOp.ADD, result, c, d); + code.returnValue(result); + code.mark(baseCase); + code.returnValue(i); + + ClassLoader loader = dexMaker.generateAndLoad( + FibonacciMaker.class.getClassLoader(), getDataDirectory(), getDataDirectory()); + Class<?> fibonacciClass = loader.loadClass("com.google.dexmaker.examples.Fibonacci"); + Method fibMethod = fibonacciClass.getMethod("fib", int.class); + System.out.println(fibMethod.invoke(null, 8)); + } + + public static File getDataDirectory() throws Exception { + Class<?> environmentClass = Class.forName("android.os.Environment"); + Method method = environmentClass.getMethod("getDataDirectory"); + Object dataDirectory = method.invoke(null); + return (File) dataDirectory; + } +} |