aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJesse Wilson <jessewilson@google.com>2012-01-06 11:14:53 -0500
committerJesse Wilson <jessewilson@google.com>2012-01-06 11:14:53 -0500
commit0e49fb9243b7463835ab80ef7cc62435f55846ce (patch)
tree6caa9d3c45c88f0fc695633d54a36c91fee70748
parentab220f004db90fa94ef9349ca1adde5f89012e8d (diff)
downloaddexmaker-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.java52
-rw-r--r--src/main/java/com/google/dexmaker/Constants.java8
-rw-r--r--src/main/java/com/google/dexmaker/DexMaker.java163
-rw-r--r--src/main/java/com/google/dexmaker/FieldId.java10
-rw-r--r--src/main/java/com/google/dexmaker/Local.java8
-rw-r--r--src/main/java/com/google/dexmaker/MethodId.java14
-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.java6
-rw-r--r--src/main/java/com/google/dexmaker/stock/ProxyBuilder.java91
-rw-r--r--src/test/java/com/google/dexmaker/DexMakerTest.java328
-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.java74
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;
+ }
+}