summaryrefslogtreecommitdiffstats
path: root/dx
diff options
context:
space:
mode:
authorJesse Wilson <jessewilson@google.com>2012-01-04 11:41:54 -0500
committerJesse Wilson <jessewilson@google.com>2012-01-04 11:51:56 -0500
commit1609c0c6ef135b56c156b5f915ed646eb400965b (patch)
treeabd2ebf68ff310f6051985869589d0b74891e349 /dx
parent26f957278b34144a3f90989ccddb0102fc1fdd62 (diff)
downloadandroid_dalvik-1609c0c6ef135b56c156b5f915ed646eb400965b.tar.gz
android_dalvik-1609c0c6ef135b56c156b5f915ed646eb400965b.tar.bz2
android_dalvik-1609c0c6ef135b56c156b5f915ed646eb400965b.zip
Remove dexmaker code from dx.
This now lives as a standalone project: http://code.google.com/p/dexmaker/ Change-Id: I4f7abff9399d6827082c9af78a015562fdbcdbb3
Diffstat (limited to 'dx')
-rw-r--r--dx/junit-tests/HelloWorldMaker.java90
-rw-r--r--dx/junit-tests/com/android/dx/gen/DexGeneratorTest.java1677
-rw-r--r--dx/junit-tests/com/android/dx/gen/ProxyBuilderTest.java536
-rw-r--r--dx/junit-tests/com/android/dx/gen/TypeTest.java30
-rw-r--r--dx/src/com/android/dx/gen/BinaryOp.java118
-rw-r--r--dx/src/com/android/dx/gen/Code.java570
-rw-r--r--dx/src/com/android/dx/gen/Comparison.java71
-rw-r--r--dx/src/com/android/dx/gen/Constants.java72
-rw-r--r--dx/src/com/android/dx/gen/DexCacheException.java28
-rw-r--r--dx/src/com/android/dx/gen/DexGenerator.java281
-rw-r--r--dx/src/com/android/dx/gen/FieldId.java71
-rw-r--r--dx/src/com/android/dx/gen/Label.java90
-rw-r--r--dx/src/com/android/dx/gen/Local.java71
-rw-r--r--dx/src/com/android/dx/gen/MethodId.java107
-rw-r--r--dx/src/com/android/dx/gen/ProxyBuilder.java667
-rw-r--r--dx/src/com/android/dx/gen/Type.java140
-rw-r--r--dx/src/com/android/dx/gen/TypeList.java64
17 files changed, 0 insertions, 4683 deletions
diff --git a/dx/junit-tests/HelloWorldMaker.java b/dx/junit-tests/HelloWorldMaker.java
deleted file mode 100644
index 038701c77..000000000
--- a/dx/junit-tests/HelloWorldMaker.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import com.android.dx.gen.BinaryOp;
-import com.android.dx.gen.Code;
-import com.android.dx.gen.DexGenerator;
-import com.android.dx.gen.FieldId;
-import com.android.dx.gen.Local;
-import com.android.dx.gen.MethodId;
-import com.android.dx.gen.Type;
-import com.android.dx.rop.code.AccessFlags;
-
-import java.io.File;
-import java.io.PrintStream;
-
-public class HelloWorldMaker {
- private static final Type<PrintStream> PRINT_STREAM = Type.get(PrintStream.class);
- private static final FieldId<System, PrintStream> SYSTEM_OUT
- = Type.get(System.class).getField(PRINT_STREAM, "out");
- private static final MethodId<Integer, String> TO_HEX_STRING
- = Type.get(Integer.class).getMethod(Type.STRING, "toHexString", Type.INT);
- private static final MethodId<PrintStream, Void> PRINTLN
- = PRINT_STREAM.getMethod(Type.VOID, "println", Type.STRING);
-
- public static void main(String[] args) throws Exception {
-
- /*
- * This code generates Dalvik bytecode equivalent to the following
- * program.
- *
- * public class HelloWorld {
- * public static void hello() {
- * int a = 0xabcd;
- * int b = 0xaaaa;
- * int c = a - b;
- * String s = Integer.toHexString(c);
- * System.out.println(s);
- * }
- * }
- */
-
- DexGenerator generator = new DexGenerator();
-
- // lookup the symbols of interest
- Type<?> helloWorld = Type.get("LHelloWorld;");
- MethodId hello = helloWorld.getMethod(Type.VOID, "hello");
-
- // create some registers
- // (I'd like a better syntax for this)
- Code code = generator.declare(hello, AccessFlags.ACC_STATIC | AccessFlags.ACC_PUBLIC);
- Local<Integer> a = code.newLocal(Type.INT);
- Local<Integer> b = code.newLocal(Type.INT);
- Local<Integer> c = code.newLocal(Type.INT);
- Local<String> s = code.newLocal(Type.STRING);
- Local<PrintStream> localSystemOut = code.newLocal(PRINT_STREAM);
-
- // specify the code instruction-by-instruction (approximately)
- code.loadConstant(a, 0xabcd);
- code.loadConstant(b, 0xaaaa);
- code.op(BinaryOp.SUBTRACT, c, a, b);
- code.invokeStatic(TO_HEX_STRING, s, c);
- code.sget(SYSTEM_OUT, localSystemOut);
- code.invokeVirtual(PRINTLN, null, localSystemOut, s);
- code.returnVoid();
-
- // TODO: create the constructor
-
- generator.declare(helloWorld, "Generated.java", AccessFlags.ACC_PUBLIC, Type.OBJECT);
-
- // load the dex
- File outputDir = new File(".");
- ClassLoader loader = generator.load(HelloWorldMaker.class.getClassLoader(),
- outputDir, outputDir);
- Class<?> helloWorldClass = loader.loadClass("HelloWorld");
- helloWorldClass.getMethod("hello").invoke(null);
- }
-}
diff --git a/dx/junit-tests/com/android/dx/gen/DexGeneratorTest.java b/dx/junit-tests/com/android/dx/gen/DexGeneratorTest.java
deleted file mode 100644
index 8dc6c8db5..000000000
--- a/dx/junit-tests/com/android/dx/gen/DexGeneratorTest.java
+++ /dev/null
@@ -1,1677 +0,0 @@
-/*
- * Copyright (C) 2011 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.android.dx.gen;
-
-import static com.android.dx.rop.code.AccessFlags.ACC_CONSTRUCTOR;
-import static com.android.dx.rop.code.AccessFlags.ACC_FINAL;
-import static com.android.dx.rop.code.AccessFlags.ACC_PRIVATE;
-import static com.android.dx.rop.code.AccessFlags.ACC_PROTECTED;
-import static com.android.dx.rop.code.AccessFlags.ACC_PUBLIC;
-import static com.android.dx.rop.code.AccessFlags.ACC_STATIC;
-
-import junit.framework.TestCase;
-
-import java.io.File;
-import java.io.IOException;
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.Arrays;
-import java.util.List;
-import java.util.concurrent.Callable;
-
-/**
- * This generates a class named 'Generated' with one or more generated methods
- * and fields. In loads the generated class into the current VM and uses
- * reflection to invoke its methods.
- *
- * <p>This test must run on a Dalvik VM.
- */
-public final class DexGeneratorTest extends TestCase {
- private DexGenerator generator;
- private static Type<DexGeneratorTest> TEST_TYPE = Type.get(DexGeneratorTest.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");
-
- @Override protected void setUp() throws Exception {
- super.setUp();
- reset();
- }
-
- /**
- * The generator is mutable. Calling reset creates a new empty generator.
- * This is necessary to generate multiple classes in the same test method.
- */
- private void reset() {
- generator = new DexGenerator();
- generator.declare(GENERATED, "Generated.java", ACC_PUBLIC, Type.OBJECT);
- }
-
- public void testNewInstance() throws Exception {
- /*
- * public static Constructable call(long a, boolean b) {
- * Constructable result = new Constructable(a, b);
- * return result;
- * }
- */
- Type<Constructable> constructable = Type.get(Constructable.class);
- MethodId<?, Constructable> methodId = GENERATED.getMethod(
- constructable, "call", Type.LONG, Type.BOOLEAN);
- Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
- Local<Long> localA = code.getParameter(0, Type.LONG);
- Local<Boolean> localB = code.getParameter(1, Type.BOOLEAN);
- MethodId<Constructable, Void> constructor
- = constructable.getConstructor(Type.LONG, Type.BOOLEAN);
- Local<Constructable> localResult = code.newLocal(constructable);
- code.newInstance(localResult, constructor, localA, localB);
- code.returnValue(localResult);
-
- Constructable constructed = (Constructable) getMethod().invoke(null, 5L, false);
- assertEquals(5L, constructed.a);
- assertEquals(false, constructed.b);
- }
-
- public static class Constructable {
- private final long a;
- private final boolean b;
- public Constructable(long a, boolean b) {
- this.a = a;
- this.b = b;
- }
- }
-
- public void testVoidNoArgMemberMethod() throws Exception {
- /*
- * public void call() {
- * }
- */
- MethodId<?, Void> methodId = GENERATED.getMethod(Type.VOID, "call");
- Code code = generator.declare(methodId, ACC_PUBLIC);
- code.returnVoid();
-
- addDefaultConstructor();
-
- Class<?> generatedClass = loadAndGenerate();
- Object instance = generatedClass.newInstance();
- Method method = generatedClass.getMethod("call");
- method.invoke(instance);
- }
-
- public void testInvokeStatic() throws Exception {
- /*
- * public static int call(int a) {
- * int result = DexGeneratorTest.staticMethod(a);
- * return result;
- * }
- */
- MethodId<?, Integer> methodId = GENERATED.getMethod(Type.INT, "call", Type.INT);
- Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
- Local<Integer> localA = code.getParameter(0, Type.INT);
- Local<Integer> localResult = code.newLocal(Type.INT);
- MethodId<?, Integer> staticMethod
- = TEST_TYPE.getMethod(Type.INT, "staticMethod", Type.INT);
- code.invokeStatic(staticMethod, localResult, localA);
- code.returnValue(localResult);
-
- assertEquals(10, getMethod().invoke(null, 4));
- }
-
- public void testCreateLocalMethodAsNull() throws Exception {
- /*
- * public void call(int value) {
- * Method method = null;
- * }
- */
- MethodId<?, Void> methodId = GENERATED.getMethod(Type.VOID, "call", Type.INT);
- Type<Method> methodType = Type.get(Method.class);
- Code code = generator.declare(methodId, ACC_PUBLIC);
- Local<Method> localMethod = code.newLocal(methodType);
- code.loadConstant(localMethod, null);
- code.returnVoid();
-
- addDefaultConstructor();
-
- Class<?> generatedClass = loadAndGenerate();
- Object instance = generatedClass.newInstance();
- Method method = generatedClass.getMethod("call", int.class);
- method.invoke(instance, 0);
- }
-
- @SuppressWarnings("unused") // called by generated code
- public static int staticMethod(int a) {
- return a + 6;
- }
-
- public void testInvokeVirtual() throws Exception {
- /*
- * public static int call(DexGeneratorTest test, int a) {
- * int result = test.virtualMethod(a);
- * return result;
- * }
- */
- MethodId<?, Integer> methodId = GENERATED.getMethod(Type.INT, "call", TEST_TYPE, Type.INT);
- Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
- Local<DexGeneratorTest> localInstance = code.getParameter(0, TEST_TYPE);
- Local<Integer> localA = code.getParameter(1, Type.INT);
- Local<Integer> localResult = code.newLocal(Type.INT);
- MethodId<DexGeneratorTest, Integer> virtualMethod
- = TEST_TYPE.getMethod(Type.INT, "virtualMethod", Type.INT);
- code.invokeVirtual(virtualMethod, localResult, localInstance, localA);
- code.returnValue(localResult);
-
- assertEquals(9, getMethod().invoke(null, this, 4));
- }
-
- @SuppressWarnings("unused") // called by generated code
- public int virtualMethod(int a) {
- return a + 5;
- }
-
- public <G> void testInvokeDirect() throws Exception {
- /*
- * private int directMethod() {
- * int a = 5;
- * return a;
- * }
- *
- * public static int call(Generated g) {
- * int b = g.directMethod();
- * return b;
- * }
- */
- Type<G> generated = Type.get("LGenerated;");
- MethodId<G, Integer> directMethodId = generated.getMethod(Type.INT, "directMethod");
- Code directCode = generator.declare(directMethodId, ACC_PRIVATE);
- directCode.getThis(generated); // 'this' is unused
- Local<Integer> localA = directCode.newLocal(Type.INT);
- directCode.loadConstant(localA, 5);
- directCode.returnValue(localA);
-
- MethodId<G, Integer> methodId = generated.getMethod(Type.INT, "call", generated);
- Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
- Local<Integer> localB = code.newLocal(Type.INT);
- Local<G> localG = code.getParameter(0, generated);
- code.invokeDirect(directMethodId, localB, localG);
- code.returnValue(localB);
-
- addDefaultConstructor();
-
- Class<?> generatedClass = loadAndGenerate();
- Object instance = generatedClass.newInstance();
- Method method = generatedClass.getMethod("call", generatedClass);
- assertEquals(5, method.invoke(null, instance));
- }
-
- public <G> void testInvokeSuper() throws Exception {
- /*
- * public int superHashCode() {
- * int result = super.hashCode();
- * return result;
- * }
- * public int hashCode() {
- * return 0;
- * }
- */
- Type<G> generated = Type.get("LGenerated;");
- MethodId<Object, Integer> objectHashCode = Type.OBJECT.getMethod(Type.INT, "hashCode");
- Code superHashCode = generator.declare(
- GENERATED.getMethod(Type.INT, "superHashCode"), ACC_PUBLIC);
- Local<Integer> localResult = superHashCode.newLocal(Type.INT);
- Local<G> localThis = superHashCode.getThis(generated);
- superHashCode.invokeSuper(objectHashCode, localResult, localThis);
- superHashCode.returnValue(localResult);
-
- Code generatedHashCode = generator.declare(
- GENERATED.getMethod(Type.INT, "hashCode"), ACC_PUBLIC);
- Local<Integer> localZero = generatedHashCode.newLocal(Type.INT);
- generatedHashCode.loadConstant(localZero, 0);
- generatedHashCode.returnValue(localZero);
-
- addDefaultConstructor();
-
- Class<?> generatedClass = loadAndGenerate();
- Object instance = generatedClass.newInstance();
- Method method = generatedClass.getMethod("superHashCode");
- assertEquals(System.identityHashCode(instance), method.invoke(instance));
- }
-
- @SuppressWarnings("unused") // called by generated code
- public int superMethod(int a) {
- return a + 4;
- }
-
- public void testInvokeInterface() throws Exception {
- /*
- * public static Object call(Callable c) {
- * Object result = c.call();
- * return result;
- * }
- */
- MethodId<?, Object> methodId = GENERATED.getMethod(Type.OBJECT, "call", CALLABLE);
- Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
- Local<Callable> localC = code.getParameter(0, CALLABLE);
- Local<Object> localResult = code.newLocal(Type.OBJECT);
- code.invokeInterface(CALL, localResult, localC);
- code.returnValue(localResult);
-
- Callable<Object> callable = new Callable<Object>() {
- public Object call() throws Exception {
- return "abc";
- }
- };
- assertEquals("abc", getMethod().invoke(null, callable));
- }
-
- public void testParameterMismatch() throws Exception {
- Type<?>[] argTypes = {
- Type.get(Integer.class), // should fail because the code specifies int
- Type.OBJECT,
- };
- MethodId<?, Integer> methodId = GENERATED.getMethod(Type.INT, "call", argTypes);
- Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
- try {
- code.getParameter(0, Type.INT);
- } catch (IllegalArgumentException e) {
- }
- try {
- code.getParameter(2, Type.INT);
- } catch (IndexOutOfBoundsException e) {
- }
- }
-
- public void testInvokeTypeSafety() throws Exception {
- /*
- * public static boolean call(DexGeneratorTest test) {
- * CharSequence cs = test.toString();
- * boolean result = cs.equals(test);
- * return result;
- * }
- */
- MethodId<?, Boolean> methodId = GENERATED.getMethod(Type.BOOLEAN, "call", TEST_TYPE);
- Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
- Local<DexGeneratorTest> localTest = code.getParameter(0, TEST_TYPE);
- Type<CharSequence> charSequenceType = Type.get(CharSequence.class);
- MethodId<Object, String> objectToString = Type.OBJECT.getMethod(Type.STRING, "toString");
- MethodId<Object, Boolean> objectEquals
- = Type.OBJECT.getMethod(Type.BOOLEAN, "equals", Type.OBJECT);
- Local<CharSequence> localCs = code.newLocal(charSequenceType);
- Local<Boolean> localResult = code.newLocal(Type.BOOLEAN);
- code.invokeVirtual(objectToString, localCs, localTest);
- code.invokeVirtual(objectEquals, localResult, localCs, localTest);
- code.returnValue(localResult);
-
- assertEquals(false, getMethod().invoke(null, this));
- }
-
- public void testReturnTypeMismatch() {
- MethodId<?, String> methodId = GENERATED.getMethod(Type.STRING, "call");
- Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
- try {
- code.returnValue(code.newLocal(Type.BOOLEAN));
- fail();
- } catch (IllegalArgumentException expected) {
- }
- try {
- code.returnVoid();
- fail();
- } catch (IllegalArgumentException expected) {
- }
- }
-
- public void testDeclareStaticFields() throws Exception {
- /*
- * class Generated {
- * public static int a;
- * protected static Object b;
- * }
- */
- generator.declare(GENERATED.getField(Type.INT, "a"), ACC_PUBLIC | ACC_STATIC, 3);
- generator.declare(GENERATED.getField(Type.OBJECT, "b"), ACC_PROTECTED | ACC_STATIC, null);
- Class<?> generatedClass = loadAndGenerate();
-
- Field a = generatedClass.getField("a");
- assertEquals(int.class, a.getType());
- assertEquals(3, a.get(null));
-
- Field b = generatedClass.getDeclaredField("b");
- assertEquals(Object.class, b.getType());
- b.setAccessible(true);
- assertEquals(null, b.get(null));
- }
-
- public void testDeclareInstanceFields() throws Exception {
- /*
- * class Generated {
- * public int a;
- * protected Object b;
- * }
- */
- generator.declare(GENERATED.getField(Type.INT, "a"), ACC_PUBLIC, null);
- generator.declare(GENERATED.getField(Type.OBJECT, "b"), ACC_PROTECTED, null);
-
- addDefaultConstructor();
-
- Class<?> generatedClass = loadAndGenerate();
- Object instance = generatedClass.newInstance();
-
- Field a = generatedClass.getField("a");
- assertEquals(int.class, a.getType());
- assertEquals(0, a.get(instance));
-
- Field b = generatedClass.getDeclaredField("b");
- assertEquals(Object.class, b.getType());
- b.setAccessible(true);
- assertEquals(null, b.get(instance));
- }
-
- /**
- * Declare a constructor that takes an int parameter and assigns it to a
- * field.
- */
- public <G> void testDeclareConstructor() throws Exception {
- /*
- * class Generated {
- * public final int a;
- * public Generated(int a) {
- * this.a = a;
- * }
- * }
- */
- Type<G> generated = Type.get("LGenerated;");
- FieldId<G, Integer> fieldId = generated.getField(Type.INT, "a");
- generator.declare(fieldId, ACC_PUBLIC | ACC_FINAL, null);
- MethodId<?, Void> constructor = GENERATED.getConstructor(Type.INT);
- Code code = generator.declare(constructor, ACC_PUBLIC | ACC_CONSTRUCTOR);
- Local<G> thisRef = code.getThis(generated);
- Local<Integer> parameter = code.getParameter(0, Type.INT);
- code.invokeDirect(Type.OBJECT.getConstructor(), null, thisRef);
- code.iput(fieldId, thisRef, parameter);
- code.returnVoid();
-
- Class<?> generatedClass = loadAndGenerate();
- Field a = generatedClass.getField("a");
- Object instance = generatedClass.getConstructor(int.class).newInstance(0xabcd);
- assertEquals(0xabcd, a.get(instance));
- }
-
- public void testReturnBoolean() throws Exception {
- testReturnType(boolean.class, true);
- testReturnType(byte.class, (byte) 5);
- testReturnType(char.class, 'E');
- testReturnType(double.class, 5.0);
- testReturnType(float.class, 5.0f);
- testReturnType(int.class, 5);
- testReturnType(long.class, 5L);
- testReturnType(short.class, (short) 5);
- testReturnType(void.class, null);
- testReturnType(String.class, "foo");
- testReturnType(Class.class, List.class);
- }
-
- private <T> void testReturnType(Class<T> javaType, T value) throws Exception {
- /*
- * public int call() {
- * int a = 5;
- * return a;
- * }
- */
- reset();
- Type<T> returnType = Type.get(javaType);
- Code code = generator.declare(GENERATED.getMethod(returnType, "call"),
- ACC_PUBLIC | ACC_STATIC);
- if (value != null) {
- Local<T> i = code.newLocal(returnType);
- code.loadConstant(i, value);
- code.returnValue(i);
- } else {
- code.returnVoid();
- }
-
- Class<?> generatedClass = loadAndGenerate();
- Method method = generatedClass.getMethod("call");
- assertEquals(javaType, method.getReturnType());
- assertEquals(value, method.invoke(null));
- }
-
- public void testBranching() throws Exception {
- Method lt = branchingMethod(Comparison.LT);
- assertEquals(Boolean.TRUE, lt.invoke(null, 1, 2));
- assertEquals(Boolean.FALSE, lt.invoke(null, 1, 1));
- assertEquals(Boolean.FALSE, lt.invoke(null, 2, 1));
-
- Method le = branchingMethod(Comparison.LE);
- assertEquals(Boolean.TRUE, le.invoke(null, 1, 2));
- assertEquals(Boolean.TRUE, le.invoke(null, 1, 1));
- assertEquals(Boolean.FALSE, le.invoke(null, 2, 1));
-
- Method eq = branchingMethod(Comparison.EQ);
- assertEquals(Boolean.FALSE, eq.invoke(null, 1, 2));
- assertEquals(Boolean.TRUE, eq.invoke(null, 1, 1));
- assertEquals(Boolean.FALSE, eq.invoke(null, 2, 1));
-
- Method ge = branchingMethod(Comparison.GE);
- assertEquals(Boolean.FALSE, ge.invoke(null, 1, 2));
- assertEquals(Boolean.TRUE, ge.invoke(null, 1, 1));
- assertEquals(Boolean.TRUE, ge.invoke(null, 2, 1));
-
- Method gt = branchingMethod(Comparison.GT);
- assertEquals(Boolean.FALSE, gt.invoke(null, 1, 2));
- assertEquals(Boolean.FALSE, gt.invoke(null, 1, 1));
- assertEquals(Boolean.TRUE, gt.invoke(null, 2, 1));
-
- Method ne = branchingMethod(Comparison.NE);
- assertEquals(Boolean.TRUE, ne.invoke(null, 1, 2));
- assertEquals(Boolean.FALSE, ne.invoke(null, 1, 1));
- assertEquals(Boolean.TRUE, ne.invoke(null, 2, 1));
- }
-
- private Method branchingMethod(Comparison comparison) throws Exception {
- /*
- * public static boolean call(int localA, int localB) {
- * if (a comparison b) {
- * return true;
- * }
- * return false;
- * }
- */
- reset();
- MethodId<?, Boolean> methodId = GENERATED.getMethod(
- Type.BOOLEAN, "call", Type.INT, Type.INT);
- Code code = generator.declare(methodId, ACC_PUBLIC | ACC_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));
- Label afterIf = code.newLabel();
- Label ifBody = code.newLabel();
- code.compare(comparison, localA, localB, ifBody);
- code.jump(afterIf);
-
- code.mark(ifBody);
- code.loadConstant(result, true);
- code.returnValue(result);
-
- code.mark(afterIf);
- code.loadConstant(result, false);
- code.returnValue(result);
- return getMethod();
- }
-
- public void testCastIntegerToInteger() throws Exception {
- Method intToLong = numericCastingMethod(int.class, long.class);
- assertEquals(0x0000000000000000L, intToLong.invoke(null, 0x00000000));
- assertEquals(0x000000007fffffffL, intToLong.invoke(null, 0x7fffffff));
- assertEquals(0xffffffff80000000L, intToLong.invoke(null, 0x80000000));
- assertEquals(0xffffffffffffffffL, intToLong.invoke(null, 0xffffffff));
-
- Method longToInt = numericCastingMethod(long.class, int.class);
- assertEquals(0x1234abcd, longToInt.invoke(null, 0x000000001234abcdL));
- assertEquals(0x1234abcd, longToInt.invoke(null, 0x123456781234abcdL));
- assertEquals(0x1234abcd, longToInt.invoke(null, 0xffffffff1234abcdL));
-
- Method intToShort = numericCastingMethod(int.class, short.class);
- assertEquals((short) 0x1234, intToShort.invoke(null, 0x00001234));
- assertEquals((short) 0x1234, intToShort.invoke(null, 0xabcd1234));
- assertEquals((short) 0x1234, intToShort.invoke(null, 0xffff1234));
-
- Method intToChar = numericCastingMethod(int.class, char.class);
- assertEquals((char) 0x1234, intToChar.invoke(null, 0x00001234));
- assertEquals((char) 0x1234, intToChar.invoke(null, 0xabcd1234));
- assertEquals((char) 0x1234, intToChar.invoke(null, 0xffff1234));
-
- Method intToByte = numericCastingMethod(int.class, byte.class);
- assertEquals((byte) 0x34, intToByte.invoke(null, 0x00000034));
- assertEquals((byte) 0x34, intToByte.invoke(null, 0xabcd1234));
- assertEquals((byte) 0x34, intToByte.invoke(null, 0xffffff34));
- }
-
- public void testCastIntegerToFloatingPoint() throws Exception {
- Method intToFloat = numericCastingMethod(int.class, float.class);
- assertEquals(0.0f, intToFloat.invoke(null, 0));
- assertEquals(-1.0f, intToFloat.invoke(null, -1));
- assertEquals(16777216f, intToFloat.invoke(null, 16777216));
- assertEquals(16777216f, intToFloat.invoke(null, 16777217)); // precision
-
- Method intToDouble = numericCastingMethod(int.class, double.class);
- assertEquals(0.0, intToDouble.invoke(null, 0));
- assertEquals(-1.0, intToDouble.invoke(null, -1));
- assertEquals(16777216.0, intToDouble.invoke(null, 16777216));
- assertEquals(16777217.0, intToDouble.invoke(null, 16777217));
-
- Method longToFloat = numericCastingMethod(long.class, float.class);
- assertEquals(0.0f, longToFloat.invoke(null, 0L));
- assertEquals(-1.0f, longToFloat.invoke(null, -1L));
- assertEquals(16777216f, longToFloat.invoke(null, 16777216L));
- assertEquals(16777216f, longToFloat.invoke(null, 16777217L));
-
- Method longToDouble = numericCastingMethod(long.class, double.class);
- assertEquals(0.0, longToDouble.invoke(null, 0L));
- assertEquals(-1.0, longToDouble.invoke(null, -1L));
- assertEquals(9007199254740992.0, longToDouble.invoke(null, 9007199254740992L));
- assertEquals(9007199254740992.0, longToDouble.invoke(null, 9007199254740993L)); // precision
- }
-
- public void testCastFloatingPointToInteger() throws Exception {
- Method floatToInt = numericCastingMethod(float.class, int.class);
- assertEquals(0, floatToInt.invoke(null, 0.0f));
- assertEquals(-1, floatToInt.invoke(null, -1.0f));
- assertEquals(Integer.MAX_VALUE, floatToInt.invoke(null, 10e15f));
- assertEquals(0, floatToInt.invoke(null, 0.5f));
- assertEquals(Integer.MIN_VALUE, floatToInt.invoke(null, Float.NEGATIVE_INFINITY));
- assertEquals(0, floatToInt.invoke(null, Float.NaN));
-
- Method floatToLong = numericCastingMethod(float.class, long.class);
- assertEquals(0L, floatToLong.invoke(null, 0.0f));
- assertEquals(-1L, floatToLong.invoke(null, -1.0f));
- assertEquals(10000000272564224L, floatToLong.invoke(null, 10e15f));
- assertEquals(0L, floatToLong.invoke(null, 0.5f));
- assertEquals(Long.MIN_VALUE, floatToLong.invoke(null, Float.NEGATIVE_INFINITY));
- assertEquals(0L, floatToLong.invoke(null, Float.NaN));
-
- Method doubleToInt = numericCastingMethod(double.class, int.class);
- assertEquals(0, doubleToInt.invoke(null, 0.0));
- assertEquals(-1, doubleToInt.invoke(null, -1.0));
- assertEquals(Integer.MAX_VALUE, doubleToInt.invoke(null, 10e15));
- assertEquals(0, doubleToInt.invoke(null, 0.5));
- assertEquals(Integer.MIN_VALUE, doubleToInt.invoke(null, Double.NEGATIVE_INFINITY));
- assertEquals(0, doubleToInt.invoke(null, Double.NaN));
-
- Method doubleToLong = numericCastingMethod(double.class, long.class);
- assertEquals(0L, doubleToLong.invoke(null, 0.0));
- assertEquals(-1L, doubleToLong.invoke(null, -1.0));
- assertEquals(10000000000000000L, doubleToLong.invoke(null, 10e15));
- assertEquals(0L, doubleToLong.invoke(null, 0.5));
- assertEquals(Long.MIN_VALUE, doubleToLong.invoke(null, Double.NEGATIVE_INFINITY));
- assertEquals(0L, doubleToLong.invoke(null, Double.NaN));
- }
-
- public void testCastFloatingPointToFloatingPoint() throws Exception {
- Method floatToDouble = numericCastingMethod(float.class, double.class);
- assertEquals(0.0, floatToDouble.invoke(null, 0.0f));
- assertEquals(-1.0, floatToDouble.invoke(null, -1.0f));
- assertEquals(0.5, floatToDouble.invoke(null, 0.5f));
- assertEquals(Double.NEGATIVE_INFINITY, floatToDouble.invoke(null, Float.NEGATIVE_INFINITY));
- assertEquals(Double.NaN, floatToDouble.invoke(null, Float.NaN));
-
- Method doubleToFloat = numericCastingMethod(double.class, float.class);
- assertEquals(0.0f, doubleToFloat.invoke(null, 0.0));
- assertEquals(-1.0f, doubleToFloat.invoke(null, -1.0));
- assertEquals(0.5f, doubleToFloat.invoke(null, 0.5));
- assertEquals(Float.NEGATIVE_INFINITY, doubleToFloat.invoke(null, Double.NEGATIVE_INFINITY));
- assertEquals(Float.NaN, doubleToFloat.invoke(null, Double.NaN));
- }
-
- private Method numericCastingMethod(Class<?> source, Class<?> target)
- throws Exception {
- /*
- * public static short call(int source) {
- * short casted = (short) source;
- * return casted;
- * }
- */
- reset();
- Type<?> sourceType = Type.get(source);
- Type<?> targetType = Type.get(target);
- MethodId<?, ?> methodId = GENERATED.getMethod(targetType, "call", sourceType);
- Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
- Local<?> localSource = code.getParameter(0, sourceType);
- Local<?> localCasted = code.newLocal(targetType);
- code.numericCast(localSource, localCasted);
- code.returnValue(localCasted);
- return getMethod();
- }
-
- public void testNot() throws Exception {
- Method notInteger = notMethod(int.class);
- assertEquals(0xffffffff, notInteger.invoke(null, 0x00000000));
- assertEquals(0x00000000, notInteger.invoke(null, 0xffffffff));
- assertEquals(0xedcba987, notInteger.invoke(null, 0x12345678));
-
- Method notLong = notMethod(long.class);
- assertEquals(0xffffffffffffffffL, notLong.invoke(null, 0x0000000000000000L));
- assertEquals(0x0000000000000000L, notLong.invoke(null, 0xffffffffffffffffL));
- assertEquals(0x98765432edcba987L, notLong.invoke(null, 0x6789abcd12345678L));
- }
-
- private <T> Method notMethod(Class<T> source) throws Exception {
- /*
- * public static short call(int source) {
- * source = ~source;
- * return not;
- * }
- */
- reset();
- Type<T> valueType = Type.get(source);
- MethodId<?, T> methodId = GENERATED.getMethod(valueType, "call", valueType);
- Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
- Local<T> localSource = code.getParameter(0, valueType);
- code.not(localSource, localSource);
- code.returnValue(localSource);
- return getMethod();
- }
-
- public void testNegate() throws Exception {
- Method negateInteger = negateMethod(int.class);
- assertEquals(0, negateInteger.invoke(null, 0));
- assertEquals(-1, negateInteger.invoke(null, 1));
- assertEquals(Integer.MIN_VALUE, negateInteger.invoke(null, Integer.MIN_VALUE));
-
- Method negateLong = negateMethod(long.class);
- assertEquals(0L, negateLong.invoke(null, 0));
- assertEquals(-1L, negateLong.invoke(null, 1));
- assertEquals(Long.MIN_VALUE, negateLong.invoke(null, Long.MIN_VALUE));
-
- Method negateFloat = negateMethod(float.class);
- assertEquals(-0.0f, negateFloat.invoke(null, 0.0f));
- assertEquals(-1.0f, negateFloat.invoke(null, 1.0f));
- assertEquals(Float.NaN, negateFloat.invoke(null, Float.NaN));
- assertEquals(Float.POSITIVE_INFINITY, negateFloat.invoke(null, Float.NEGATIVE_INFINITY));
-
- Method negateDouble = negateMethod(double.class);
- assertEquals(-0.0, negateDouble.invoke(null, 0.0));
- assertEquals(-1.0, negateDouble.invoke(null, 1.0));
- assertEquals(Double.NaN, negateDouble.invoke(null, Double.NaN));
- assertEquals(Double.POSITIVE_INFINITY, negateDouble.invoke(null, Double.NEGATIVE_INFINITY));
- }
-
- private <T> Method negateMethod(Class<T> source) throws Exception {
- /*
- * public static short call(int source) {
- * source = -source;
- * return not;
- * }
- */
- reset();
- Type<T> valueType = Type.get(source);
- MethodId<?, T> methodId = GENERATED.getMethod(valueType, "call", valueType);
- Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
- Local<T> localSource = code.getParameter(0, valueType);
- code.negate(localSource, localSource);
- code.returnValue(localSource);
- return getMethod();
- }
-
- public void testIntBinaryOps() throws Exception {
- Method add = binaryOpMethod(int.class, BinaryOp.ADD);
- assertEquals(79, add.invoke(null, 75, 4));
-
- Method subtract = binaryOpMethod(int.class, BinaryOp.SUBTRACT);
- assertEquals(71, subtract.invoke(null, 75, 4));
-
- Method multiply = binaryOpMethod(int.class, BinaryOp.MULTIPLY);
- assertEquals(300, multiply.invoke(null, 75, 4));
-
- Method divide = binaryOpMethod(int.class, BinaryOp.DIVIDE);
- assertEquals(18, divide.invoke(null, 75, 4));
- try {
- divide.invoke(null, 75, 0);
- fail();
- } catch (InvocationTargetException expected) {
- assertEquals(ArithmeticException.class, expected.getCause().getClass());
- }
-
- Method remainder = binaryOpMethod(int.class, BinaryOp.REMAINDER);
- assertEquals(3, remainder.invoke(null, 75, 4));
- try {
- remainder.invoke(null, 75, 0);
- fail();
- } catch (InvocationTargetException expected) {
- assertEquals(ArithmeticException.class, expected.getCause().getClass());
- }
-
- Method and = binaryOpMethod(int.class, BinaryOp.AND);
- assertEquals(0xff000000, and.invoke(null, 0xff00ff00, 0xffff0000));
-
- Method or = binaryOpMethod(int.class, BinaryOp.OR);
- assertEquals(0xffffff00, or.invoke(null, 0xff00ff00, 0xffff0000));
-
- Method xor = binaryOpMethod(int.class, BinaryOp.XOR);
- assertEquals(0x00ffff00, xor.invoke(null, 0xff00ff00, 0xffff0000));
-
- Method shiftLeft = binaryOpMethod(int.class, BinaryOp.SHIFT_LEFT);
- assertEquals(0xcd123400, shiftLeft.invoke(null, 0xabcd1234, 8));
-
- Method shiftRight = binaryOpMethod(int.class, BinaryOp.SHIFT_RIGHT);
- assertEquals(0xffabcd12, shiftRight.invoke(null, 0xabcd1234, 8));
-
- Method unsignedShiftRight = binaryOpMethod(int.class,
- BinaryOp.UNSIGNED_SHIFT_RIGHT);
- assertEquals(0x00abcd12, unsignedShiftRight.invoke(null, 0xabcd1234, 8));
- }
-
- public void testLongBinaryOps() throws Exception {
- Method add = binaryOpMethod(long.class, BinaryOp.ADD);
- assertEquals(79L, add.invoke(null, 75L, 4L));
-
- Method subtract = binaryOpMethod(long.class, BinaryOp.SUBTRACT);
- assertEquals(71L, subtract.invoke(null, 75L, 4L));
-
- Method multiply = binaryOpMethod(long.class, BinaryOp.MULTIPLY);
- assertEquals(300L, multiply.invoke(null, 75L, 4L));
-
- Method divide = binaryOpMethod(long.class, BinaryOp.DIVIDE);
- assertEquals(18L, divide.invoke(null, 75L, 4L));
- try {
- divide.invoke(null, 75L, 0L);
- fail();
- } catch (InvocationTargetException expected) {
- assertEquals(ArithmeticException.class, expected.getCause().getClass());
- }
-
- Method remainder = binaryOpMethod(long.class, BinaryOp.REMAINDER);
- assertEquals(3L, remainder.invoke(null, 75L, 4L));
- try {
- remainder.invoke(null, 75L, 0L);
- fail();
- } catch (InvocationTargetException expected) {
- assertEquals(ArithmeticException.class, expected.getCause().getClass());
- }
-
- Method and = binaryOpMethod(long.class, BinaryOp.AND);
- assertEquals(0xff00ff0000000000L,
- and.invoke(null, 0xff00ff00ff00ff00L, 0xffffffff00000000L));
-
- Method or = binaryOpMethod(long.class, BinaryOp.OR);
- assertEquals(0xffffffffff00ff00L,
- or.invoke(null, 0xff00ff00ff00ff00L, 0xffffffff00000000L));
-
- Method xor = binaryOpMethod(long.class, BinaryOp.XOR);
- assertEquals(0x00ff00ffff00ff00L,
- xor.invoke(null, 0xff00ff00ff00ff00L, 0xffffffff00000000L));
-
- Method shiftLeft = binaryOpMethod(long.class, BinaryOp.SHIFT_LEFT);
- assertEquals(0xcdef012345678900L, shiftLeft.invoke(null, 0xabcdef0123456789L, 8L));
-
- Method shiftRight = binaryOpMethod(long.class, BinaryOp.SHIFT_RIGHT);
- assertEquals(0xffabcdef01234567L, shiftRight.invoke(null, 0xabcdef0123456789L, 8L));
-
- Method unsignedShiftRight = binaryOpMethod(long.class,
- BinaryOp.UNSIGNED_SHIFT_RIGHT);
- assertEquals(0x00abcdef01234567L, unsignedShiftRight.invoke(null, 0xabcdef0123456789L, 8L));
- }
-
- public void testFloatBinaryOps() throws Exception {
- Method add = binaryOpMethod(float.class, BinaryOp.ADD);
- assertEquals(6.75f, add.invoke(null, 5.5f, 1.25f));
-
- Method subtract = binaryOpMethod(float.class, BinaryOp.SUBTRACT);
- assertEquals(4.25f, subtract.invoke(null, 5.5f, 1.25f));
-
- Method multiply = binaryOpMethod(float.class, BinaryOp.MULTIPLY);
- assertEquals(6.875f, multiply.invoke(null, 5.5f, 1.25f));
-
- Method divide = binaryOpMethod(float.class, BinaryOp.DIVIDE);
- assertEquals(4.4f, divide.invoke(null, 5.5f, 1.25f));
- assertEquals(Float.POSITIVE_INFINITY, divide.invoke(null, 5.5f, 0.0f));
-
- Method remainder = binaryOpMethod(float.class, BinaryOp.REMAINDER);
- assertEquals(0.5f, remainder.invoke(null, 5.5f, 1.25f));
- assertEquals(Float.NaN, remainder.invoke(null, 5.5f, 0.0f));
- }
-
- public void testDoubleBinaryOps() throws Exception {
- Method add = binaryOpMethod(double.class, BinaryOp.ADD);
- assertEquals(6.75, add.invoke(null, 5.5, 1.25));
-
- Method subtract = binaryOpMethod(double.class, BinaryOp.SUBTRACT);
- assertEquals(4.25, subtract.invoke(null, 5.5, 1.25));
-
- Method multiply = binaryOpMethod(double.class, BinaryOp.MULTIPLY);
- assertEquals(6.875, multiply.invoke(null, 5.5, 1.25));
-
- Method divide = binaryOpMethod(double.class, BinaryOp.DIVIDE);
- assertEquals(4.4, divide.invoke(null, 5.5, 1.25));
- assertEquals(Double.POSITIVE_INFINITY, divide.invoke(null, 5.5, 0.0));
-
- Method remainder = binaryOpMethod(double.class, BinaryOp.REMAINDER);
- assertEquals(0.5, remainder.invoke(null, 5.5, 1.25));
- assertEquals(Double.NaN, remainder.invoke(null, 5.5, 0.0));
- }
-
- private <T> Method binaryOpMethod(Class<T> valueClass, BinaryOp op)
- throws Exception {
- /*
- * public static int binaryOp(int a, int b) {
- * int result = a + b;
- * return result;
- * }
- */
- reset();
- Type<T> valueType = Type.get(valueClass);
- MethodId<?, T> methodId = GENERATED.getMethod(valueType, "call", valueType, valueType);
- Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
- Local<T> localA = code.getParameter(0, valueType);
- Local<T> localB = code.getParameter(1, valueType);
- Local<T> localResult = code.newLocal(valueType);
- code.op(op, localResult, localA, localB);
- code.returnValue(localResult);
- return getMethod();
- }
-
- public void testReadAndWriteInstanceFields() throws Exception {
- Instance instance = new Instance();
-
- Method intSwap = instanceSwapMethod(int.class, "intValue");
- instance.intValue = 5;
- assertEquals(5, intSwap.invoke(null, instance, 10));
- assertEquals(10, instance.intValue);
-
- Method longSwap = instanceSwapMethod(long.class, "longValue");
- instance.longValue = 500L;
- assertEquals(500L, longSwap.invoke(null, instance, 1234L));
- assertEquals(1234L, instance.longValue);
-
- Method booleanSwap = instanceSwapMethod(boolean.class, "booleanValue");
- instance.booleanValue = false;
- assertEquals(false, booleanSwap.invoke(null, instance, true));
- assertEquals(true, instance.booleanValue);
-
- Method floatSwap = instanceSwapMethod(float.class, "floatValue");
- instance.floatValue = 1.5f;
- assertEquals(1.5f, floatSwap.invoke(null, instance, 0.5f));
- assertEquals(0.5f, instance.floatValue);
-
- Method doubleSwap = instanceSwapMethod(double.class, "doubleValue");
- instance.doubleValue = 155.5;
- assertEquals(155.5, doubleSwap.invoke(null, instance, 266.6));
- assertEquals(266.6, instance.doubleValue);
-
- Method objectSwap = instanceSwapMethod(Object.class, "objectValue");
- instance.objectValue = "before";
- assertEquals("before", objectSwap.invoke(null, instance, "after"));
- assertEquals("after", instance.objectValue);
-
- Method byteSwap = instanceSwapMethod(byte.class, "byteValue");
- instance.byteValue = 0x35;
- assertEquals((byte) 0x35, byteSwap.invoke(null, instance, (byte) 0x64));
- assertEquals((byte) 0x64, instance.byteValue);
-
- Method charSwap = instanceSwapMethod(char.class, "charValue");
- instance.charValue = 'A';
- assertEquals('A', charSwap.invoke(null, instance, 'B'));
- assertEquals('B', instance.charValue);
-
- Method shortSwap = instanceSwapMethod(short.class, "shortValue");
- instance.shortValue = (short) 0xabcd;
- assertEquals((short) 0xabcd, shortSwap.invoke(null, instance, (short) 0x1234));
- assertEquals((short) 0x1234, instance.shortValue);
- }
-
- public class Instance {
- public int intValue;
- public long longValue;
- public float floatValue;
- public double doubleValue;
- public Object objectValue;
- public boolean booleanValue;
- public byte byteValue;
- public char charValue;
- public short shortValue;
- }
-
- private <V> Method instanceSwapMethod(
- Class<V> valueClass, String fieldName) throws Exception {
- /*
- * public static int call(Instance instance, int newValue) {
- * int oldValue = instance.intValue;
- * instance.intValue = newValue;
- * return oldValue;
- * }
- */
- reset();
- Type<V> valueType = Type.get(valueClass);
- Type<Instance> objectType = Type.get(Instance.class);
- FieldId<Instance, V> fieldId = objectType.getField(valueType, fieldName);
- MethodId<?, V> methodId = GENERATED.getMethod(valueType, "call", objectType, valueType);
- Code code = generator.declare(methodId, ACC_PUBLIC | ACC_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.iput(fieldId, localInstance, localNewValue);
- code.returnValue(localOldValue);
- return getMethod();
- }
-
- public void testReadAndWriteStaticFields() throws Exception {
- Method intSwap = staticSwapMethod(int.class, "intValue");
- Static.intValue = 5;
- assertEquals(5, intSwap.invoke(null, 10));
- assertEquals(10, Static.intValue);
-
- Method longSwap = staticSwapMethod(long.class, "longValue");
- Static.longValue = 500L;
- assertEquals(500L, longSwap.invoke(null, 1234L));
- assertEquals(1234L, Static.longValue);
-
- Method booleanSwap = staticSwapMethod(boolean.class, "booleanValue");
- Static.booleanValue = false;
- assertEquals(false, booleanSwap.invoke(null, true));
- assertEquals(true, Static.booleanValue);
-
- Method floatSwap = staticSwapMethod(float.class, "floatValue");
- Static.floatValue = 1.5f;
- assertEquals(1.5f, floatSwap.invoke(null, 0.5f));
- assertEquals(0.5f, Static.floatValue);
-
- Method doubleSwap = staticSwapMethod(double.class, "doubleValue");
- Static.doubleValue = 155.5;
- assertEquals(155.5, doubleSwap.invoke(null, 266.6));
- assertEquals(266.6, Static.doubleValue);
-
- Method objectSwap = staticSwapMethod(Object.class, "objectValue");
- Static.objectValue = "before";
- assertEquals("before", objectSwap.invoke(null, "after"));
- assertEquals("after", Static.objectValue);
-
- Method byteSwap = staticSwapMethod(byte.class, "byteValue");
- Static.byteValue = 0x35;
- assertEquals((byte) 0x35, byteSwap.invoke(null, (byte) 0x64));
- assertEquals((byte) 0x64, Static.byteValue);
-
- Method charSwap = staticSwapMethod(char.class, "charValue");
- Static.charValue = 'A';
- assertEquals('A', charSwap.invoke(null, 'B'));
- assertEquals('B', Static.charValue);
-
- Method shortSwap = staticSwapMethod(short.class, "shortValue");
- Static.shortValue = (short) 0xabcd;
- assertEquals((short) 0xabcd, shortSwap.invoke(null, (short) 0x1234));
- assertEquals((short) 0x1234, Static.shortValue);
- }
-
- public static class Static {
- public static int intValue;
- public static long longValue;
- public static float floatValue;
- public static double doubleValue;
- public static Object objectValue;
- public static boolean booleanValue;
- public static byte byteValue;
- public static char charValue;
- public static short shortValue;
- }
-
- private <V> Method staticSwapMethod(Class<V> valueClass, String fieldName)
- throws Exception {
- /*
- * public static int call(int newValue) {
- * int oldValue = Static.intValue;
- * Static.intValue = newValue;
- * return oldValue;
- * }
- */
- reset();
- Type<V> valueType = Type.get(valueClass);
- Type<Static> objectType = Type.get(Static.class);
- FieldId<Static, V> fieldId = objectType.getField(valueType, fieldName);
- MethodId<?, V> methodId = GENERATED.getMethod(valueType, "call", valueType);
- Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
- Local<V> localNewValue = code.getParameter(0, valueType);
- Local<V> localOldValue = code.newLocal(valueType);
- code.sget(fieldId, localOldValue);
- code.sput(fieldId, localNewValue);
- code.returnValue(localOldValue);
- return getMethod();
- }
-
- public void testTypeCast() throws Exception {
- /*
- * public static String call(Object o) {
- * String s = (String) o;
- * }
- */
- MethodId<?, String> methodId = GENERATED.getMethod(Type.STRING, "call", Type.OBJECT);
- Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
- Local<Object> localObject = code.getParameter(0, Type.OBJECT);
- Local<String> localString = code.newLocal(Type.STRING);
- code.typeCast(localObject, localString);
- code.returnValue(localString);
-
- Method method = getMethod();
- assertEquals("s", method.invoke(null, "s"));
- assertEquals(null, method.invoke(null, (String) null));
- try {
- method.invoke(null, 5);
- fail();
- } catch (InvocationTargetException expected) {
- assertEquals(ClassCastException.class, expected.getCause().getClass());
- }
- }
-
- public void testInstanceOf() throws Exception {
- /*
- * public static boolean call(Object o) {
- * boolean result = o instanceof String;
- * return result;
- * }
- */
- MethodId<?, Boolean> methodId = GENERATED.getMethod(Type.BOOLEAN, "call", Type.OBJECT);
- Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
- Local<Object> localObject = code.getParameter(0, Type.OBJECT);
- Local<Boolean> localResult = code.newLocal(Type.BOOLEAN);
- code.instanceOfType(localResult, localObject, Type.STRING);
- code.returnValue(localResult);
-
- Method method = getMethod();
- assertEquals(true, method.invoke(null, "s"));
- assertEquals(false, method.invoke(null, (String) null));
- assertEquals(false, method.invoke(null, 5));
- }
-
- /**
- * Tests that we can construct a for loop.
- */
- public void testForLoop() throws Exception {
- /*
- * public static int call(int count) {
- * int result = 1;
- * for (int i = 0; i < count; i += 1) {
- * result = result * 2;
- * }
- * return result;
- * }
- */
- MethodId<?, Integer> methodId = GENERATED.getMethod(Type.INT, "call", Type.INT);
- Code code = generator.declare(methodId, ACC_PUBLIC | ACC_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);
- code.loadConstant(local1, 1);
- code.loadConstant(local2, 2);
- code.loadConstant(localResult, 1);
- code.loadConstant(localI, 0);
- Label loopCondition = code.newLabel();
- Label loopBody = code.newLabel();
- Label afterLoop = code.newLabel();
- code.mark(loopCondition);
- code.compare(Comparison.LT, localI, localCount, loopBody);
- code.jump(afterLoop);
- code.mark(loopBody);
- code.op(BinaryOp.MULTIPLY, localResult, localResult, local2);
- code.op(BinaryOp.ADD, localI, localI, local1);
- code.jump(loopCondition);
- code.mark(afterLoop);
- code.returnValue(localResult);
-
- Method pow2 = getMethod();
- assertEquals(1, pow2.invoke(null, 0));
- assertEquals(2, pow2.invoke(null, 1));
- assertEquals(4, pow2.invoke(null, 2));
- assertEquals(8, pow2.invoke(null, 3));
- assertEquals(16, pow2.invoke(null, 4));
- }
-
- /**
- * Tests that we can construct a while loop.
- */
- public void testWhileLoop() throws Exception {
- /*
- * public static int call(int max) {
- * int result = 1;
- * while (result < max) {
- * result = result * 2;
- * }
- * return result;
- * }
- */
- MethodId<?, Integer> methodId = GENERATED.getMethod(Type.INT, "call", Type.INT);
- Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
- Local<Integer> localMax = code.getParameter(0, Type.INT);
- Local<Integer> localResult = code.newLocal(Type.INT);
- Local<Integer> local2 = code.newLocal(Type.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.jump(afterLoop);
- code.mark(loopBody);
- code.op(BinaryOp.MULTIPLY, localResult, localResult, local2);
- code.jump(loopCondition);
- code.mark(afterLoop);
- code.returnValue(localResult);
-
- Method ceilPow2 = getMethod();
- assertEquals(1, ceilPow2.invoke(null, 1));
- assertEquals(2, ceilPow2.invoke(null, 2));
- assertEquals(4, ceilPow2.invoke(null, 3));
- assertEquals(16, ceilPow2.invoke(null, 10));
- assertEquals(128, ceilPow2.invoke(null, 100));
- assertEquals(1024, ceilPow2.invoke(null, 1000));
- }
-
- public void testIfElseBlock() throws Exception {
- /*
- * public static int call(int a, int b, int c) {
- * if (a < b) {
- * if (a < c) {
- * return a;
- * } else {
- * return c;
- * }
- * } else if (b < c) {
- * return b;
- * } else {
- * return c;
- * }
- * }
- */
- MethodId<?, Integer> methodId = GENERATED.getMethod(
- Type.INT, "call", Type.INT, Type.INT, Type.INT);
- Code code = generator.declare(methodId, ACC_PUBLIC | ACC_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);
- 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.returnValue(localC);
- // (a < b)
- code.mark(aLessThanB);
- code.compare(Comparison.LT, localA, localC, aLessThanC);
- code.returnValue(localC);
- // (a < c)
- code.mark(aLessThanC);
- code.returnValue(localA);
- // (b < c)
- code.mark(bLessThanC);
- code.returnValue(localB);
-
- Method min = getMethod();
- assertEquals(1, min.invoke(null, 1, 2, 3));
- assertEquals(1, min.invoke(null, 2, 3, 1));
- assertEquals(1, min.invoke(null, 2, 1, 3));
- assertEquals(1, min.invoke(null, 3, 2, 1));
- }
-
- public void testRecursion() throws Exception {
- /*
- * public static int call(int a) {
- * if (a < 2) {
- * return a;
- * }
- * a -= 1;
- * int x = call(a)
- * a -= 1;
- * int y = call(a);
- * int result = x + y;
- * return result;
- * }
- */
- MethodId<?, Integer> methodId = GENERATED.getMethod(Type.INT, "call", Type.INT);
- Code code = generator.declare(methodId, ACC_PUBLIC | ACC_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);
- Label baseCase = code.newLabel();
- code.loadConstant(local1, 1);
- code.loadConstant(local2, 2);
- code.compare(Comparison.LT, localA, local2, baseCase);
- code.op(BinaryOp.SUBTRACT, localA, localA, local1);
- code.invokeStatic(methodId, localX, localA);
- code.op(BinaryOp.SUBTRACT, localA, localA, local1);
- code.invokeStatic(methodId, localY, localA);
- code.op(BinaryOp.ADD, localResult, localX, localY);
- code.returnValue(localResult);
- code.mark(baseCase);
- code.returnValue(localA);
-
- Method fib = getMethod();
- assertEquals(0, fib.invoke(null, 0));
- assertEquals(1, fib.invoke(null, 1));
- assertEquals(1, fib.invoke(null, 2));
- assertEquals(2, fib.invoke(null, 3));
- assertEquals(3, fib.invoke(null, 4));
- assertEquals(5, fib.invoke(null, 5));
- assertEquals(8, fib.invoke(null, 6));
- }
-
- public void testCatchExceptions() throws Exception {
- /*
- * public static String call(int i) {
- * try {
- * DexGeneratorTest.thrower(i);
- * return "NONE";
- * } catch (IllegalArgumentException e) {
- * return "IAE";
- * } catch (IllegalStateException e) {
- * return "ISE";
- * } catch (RuntimeException e) {
- * return "RE";
- * }
- */
- MethodId<?, String> methodId = GENERATED.getMethod(Type.STRING, "call", Type.INT);
- Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
- Local<Integer> localI = code.getParameter(0, Type.INT);
- Local<String> result = code.newLocal(Type.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.invokeStatic(thrower, null, localI);
- code.loadConstant(result, "NONE");
- code.returnValue(result);
-
- code.mark(catchIae);
- code.loadConstant(result, "IAE");
- code.returnValue(result);
-
- code.mark(catchIse);
- code.loadConstant(result, "ISE");
- code.returnValue(result);
-
- code.mark(catchRe);
- code.loadConstant(result, "RE");
- code.returnValue(result);
-
- Method method = getMethod();
- assertEquals("NONE", method.invoke(null, 0));
- assertEquals("IAE", method.invoke(null, 1));
- assertEquals("ISE", method.invoke(null, 2));
- assertEquals("RE", method.invoke(null, 3));
- try {
- method.invoke(null, 4);
- fail();
- } catch (InvocationTargetException expected) {
- assertEquals(IOException.class, expected.getCause().getClass());
- }
- }
-
- @SuppressWarnings("unused") // called by generated code
- public static void thrower(int a) throws Exception {
- switch (a) {
- case 0:
- return;
- case 1:
- throw new IllegalArgumentException();
- case 2:
- throw new IllegalStateException();
- case 3:
- throw new UnsupportedOperationException();
- case 4:
- throw new IOException();
- default:
- throw new AssertionError();
- }
- }
-
- public void testNestedCatchClauses() throws Exception {
- /*
- * public static String call(int a, int b, int c) {
- * try {
- * DexGeneratorTest.thrower(a);
- * try {
- * DexGeneratorTest.thrower(b);
- * } catch (IllegalArgumentException) {
- * return "INNER";
- * }
- * DexGeneratorTest.thrower(c);
- * return "NONE";
- * } catch (IllegalArgumentException e) {
- * return "OUTER";
- * }
- */
- MethodId<?, String> methodId = GENERATED.getMethod(
- Type.STRING, "call", Type.INT, Type.INT, Type.INT);
- Code code = generator.declare(methodId, ACC_PUBLIC | ACC_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);
- Label catchInner = code.newLabel();
- Label catchOuter = code.newLabel();
-
- Type<IllegalArgumentException> iaeType = Type.get(IllegalArgumentException.class);
- code.addCatchClause(iaeType, catchOuter);
-
- MethodId<?, ?> thrower = TEST_TYPE.getMethod(Type.VOID, "thrower", Type.INT);
- code.invokeStatic(thrower, null, localA);
-
- // for the inner catch clause, we stash the old label and put it back afterwards.
- Label previousLabel = code.removeCatchClause(iaeType);
- code.addCatchClause(iaeType, catchInner);
- code.invokeStatic(thrower, null, localB);
- code.removeCatchClause(iaeType);
- code.addCatchClause(iaeType, previousLabel);
- code.invokeStatic(thrower, null, localC);
- code.loadConstant(localResult, "NONE");
- code.returnValue(localResult);
-
- code.mark(catchInner);
- code.loadConstant(localResult, "INNER");
- code.returnValue(localResult);
-
- code.mark(catchOuter);
- code.loadConstant(localResult, "OUTER");
- code.returnValue(localResult);
-
- Method method = getMethod();
- assertEquals("OUTER", method.invoke(null, 1, 0, 0));
- assertEquals("INNER", method.invoke(null, 0, 1, 0));
- assertEquals("OUTER", method.invoke(null, 0, 0, 1));
- assertEquals("NONE", method.invoke(null, 0, 0, 0));
- }
-
- public void testThrow() throws Exception {
- /*
- * public static void call() {
- * throw new IllegalStateException();
- * }
- */
- MethodId<?, Void> methodId = GENERATED.getMethod(Type.VOID, "call");
- Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
- Type<IllegalStateException> iseType = Type.get(IllegalStateException.class);
- MethodId<IllegalStateException, Void> iseConstructor = iseType.getConstructor();
- Local<IllegalStateException> localIse = code.newLocal(iseType);
- code.newInstance(localIse, iseConstructor);
- code.throwValue(localIse);
-
- try {
- getMethod().invoke(null);
- fail();
- } catch (InvocationTargetException expected) {
- assertEquals(IllegalStateException.class, expected.getCause().getClass());
- }
- }
-
- public void testUnusedParameters() throws Exception {
- /*
- * public static void call(int unused1, long unused2, long unused3) {}
- */
- MethodId<?, Void> methodId = GENERATED.getMethod(
- Type.VOID, "call", Type.INT, Type.LONG, Type.LONG);
- Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
- code.returnVoid();
- getMethod().invoke(null, 1, 2, 3);
- }
-
- public void testFloatingPointCompare() throws Exception {
- Method floatG = floatingPointCompareMethod(Type.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));
- assertEquals(1, floatG.invoke(null, 2.0f, 1.0f));
- assertEquals(1, floatG.invoke(null, 1.0f, Float.NaN));
- assertEquals(1, floatG.invoke(null, Float.NaN, 1.0f));
- 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);
- 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));
- assertEquals(1, floatL.invoke(null, 2.0f, 1.0f));
- assertEquals(-1, floatL.invoke(null, 1.0f, Float.NaN));
- assertEquals(-1, floatL.invoke(null, Float.NaN, 1.0f));
- 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);
- 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));
- assertEquals(1, doubleG.invoke(null, 2.0, 1.0));
- assertEquals(1, doubleG.invoke(null, 1.0, Double.NaN));
- assertEquals(1, doubleG.invoke(null, Double.NaN, 1.0));
- 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);
- 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));
- assertEquals(1, doubleL.invoke(null, 2.0, 1.0));
- assertEquals(-1, doubleL.invoke(null, 1.0, Double.NaN));
- assertEquals(-1, doubleL.invoke(null, Double.NaN, 1.0));
- assertEquals(-1, doubleL.invoke(null, Double.NaN, Double.NaN));
- assertEquals(-1, doubleL.invoke(null, Double.NaN, Double.POSITIVE_INFINITY));
- }
-
- private <T extends Number> Method floatingPointCompareMethod(
- Type<T> valueType, int nanValue) throws Exception {
- /*
- * public static int call(float a, float b) {
- * int result = a <=> b;
- * return result;
- * }
- */
- reset();
- MethodId<?, Integer> methodId = GENERATED.getMethod(Type.INT, "call", valueType, valueType);
- Code code = generator.declare(methodId, ACC_PUBLIC | ACC_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);
- code.returnValue(localResult);
- return getMethod();
- }
-
- public void testLongCompare() throws Exception {
- /*
- * public static int call(long a, long b) {
- * int result = a <=> b;
- * return result;
- * }
- */
- MethodId<?, Integer> methodId = GENERATED.getMethod(Type.INT, "call", Type.LONG, Type.LONG);
- Code code = generator.declare(methodId, ACC_PUBLIC | ACC_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);
- code.returnValue(localResult);
-
- Method method = getMethod();
- assertEquals(0, method.invoke(null, Long.MIN_VALUE, Long.MIN_VALUE));
- assertEquals(-1, method.invoke(null, Long.MIN_VALUE, 0));
- assertEquals(-1, method.invoke(null, Long.MIN_VALUE, Long.MAX_VALUE));
- assertEquals(1, method.invoke(null, 0, Long.MIN_VALUE));
- assertEquals(0, method.invoke(null, 0, 0));
- assertEquals(-1, method.invoke(null, 0, Long.MAX_VALUE));
- assertEquals(1, method.invoke(null, Long.MAX_VALUE, Long.MIN_VALUE));
- assertEquals(1, method.invoke(null, Long.MAX_VALUE, 0));
- assertEquals(0, method.invoke(null, Long.MAX_VALUE, Long.MAX_VALUE));
- }
-
- public void testArrayLength() throws Exception {
- Method booleanArrayLength = arrayLengthMethod(BOOLEAN_ARRAY);
- assertEquals(0, booleanArrayLength.invoke(null, new Object[] { new boolean[0] }));
- assertEquals(5, booleanArrayLength.invoke(null, new Object[] { new boolean[5] }));
-
- Method intArrayLength = arrayLengthMethod(INT_ARRAY);
- assertEquals(0, intArrayLength.invoke(null, new Object[] { new int[0] }));
- assertEquals(5, intArrayLength.invoke(null, new Object[] { new int[5] }));
-
- Method longArrayLength = arrayLengthMethod(LONG_ARRAY);
- assertEquals(0, longArrayLength.invoke(null, new Object[] { new long[0] }));
- assertEquals(5, longArrayLength.invoke(null, new Object[] { new long[5] }));
-
- Method objectArrayLength = arrayLengthMethod(OBJECT_ARRAY);
- assertEquals(0, objectArrayLength.invoke(null, new Object[] { new Object[0] }));
- assertEquals(5, objectArrayLength.invoke(null, new Object[] { new Object[5] }));
-
- Method long2dArrayLength = arrayLengthMethod(LONG_2D_ARRAY);
- assertEquals(0, long2dArrayLength.invoke(null, new Object[] { new long[0][0] }));
- assertEquals(5, long2dArrayLength.invoke(null, new Object[] { new long[5][10] }));
- }
-
- private <T> Method arrayLengthMethod(Type<T> valueType) throws Exception {
- /*
- * public static int call(long[] array) {
- * int result = array.length;
- * return result;
- * }
- */
- reset();
- MethodId<?, Integer> methodId = GENERATED.getMethod(Type.INT, "call", valueType);
- Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
- Local<T> localArray = code.getParameter(0, valueType);
- Local<Integer> localResult = code.newLocal(Type.INT);
- code.arrayLength(localArray, localResult);
- code.returnValue(localResult);
- return getMethod();
- }
-
- public void testNewArray() throws Exception {
- Method newBooleanArray = newArrayMethod(BOOLEAN_ARRAY);
- assertEquals("[]", Arrays.toString((boolean[]) newBooleanArray.invoke(null, 0)));
- assertEquals("[false, false, false]",
- Arrays.toString((boolean[]) newBooleanArray.invoke(null, 3)));
-
- Method newIntArray = newArrayMethod(INT_ARRAY);
- assertEquals("[]", Arrays.toString((int[]) newIntArray.invoke(null, 0)));
- assertEquals("[0, 0, 0]", Arrays.toString((int[]) newIntArray.invoke(null, 3)));
-
- Method newLongArray = newArrayMethod(LONG_ARRAY);
- assertEquals("[]", Arrays.toString((long[]) newLongArray.invoke(null, 0)));
- assertEquals("[0, 0, 0]", Arrays.toString((long[]) newLongArray.invoke(null, 3)));
-
- Method newObjectArray = newArrayMethod(OBJECT_ARRAY);
- assertEquals("[]", Arrays.toString((Object[]) newObjectArray.invoke(null, 0)));
- assertEquals("[null, null, null]",
- Arrays.toString((Object[]) newObjectArray.invoke(null, 3)));
-
- Method new2dLongArray = newArrayMethod(LONG_2D_ARRAY);
- assertEquals("[]", Arrays.deepToString((long[][]) new2dLongArray.invoke(null, 0)));
- assertEquals("[null, null, null]",
- Arrays.deepToString((long[][]) new2dLongArray.invoke(null, 3)));
- }
-
- private <T> Method newArrayMethod(Type<T> valueType) throws Exception {
- /*
- * public static long[] call(int length) {
- * long[] result = new long[length];
- * return result;
- * }
- */
- reset();
- MethodId<?, T> methodId = GENERATED.getMethod(valueType, "call", Type.INT);
- Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
- Local<Integer> localLength = code.getParameter(0, Type.INT);
- Local<T> localResult = code.newLocal(valueType);
- code.newArray(localLength, localResult);
- code.returnValue(localResult);
- return getMethod();
- }
-
- public void testReadAndWriteArray() throws Exception {
- Method swapBooleanArray = arraySwapMethod(BOOLEAN_ARRAY, Type.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);
- 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);
- 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);
- Object[] objects = new Object[3];
- assertEquals(null, swapObjectArray.invoke(null, objects, 1, "X"));
- assertEquals("[null, X, null]", Arrays.toString(objects));
-
- Method swapLong2dArray = arraySwapMethod(LONG_2D_ARRAY, LONG_ARRAY);
- long[][] longs2d = new long[3][];
- assertEquals(null, swapLong2dArray.invoke(null, longs2d, 1, new long[] { 7 }));
- assertEquals("[null, [7], null]", Arrays.deepToString(longs2d));
- }
-
- private <A, T> Method arraySwapMethod(Type<A> arrayType, Type<T> singleType)
- throws Exception {
- /*
- * public static long swap(long[] array, int index, long newValue) {
- * long result = array[index];
- * array[index] = newValue;
- * return result;
- * }
- */
- reset();
- MethodId<?, T> methodId = GENERATED.getMethod(
- singleType, "call", arrayType, Type.INT, singleType);
- Code code = generator.declare(methodId, ACC_PUBLIC | ACC_STATIC);
- Local<A> localArray = code.getParameter(0, arrayType);
- Local<Integer> localIndex = code.getParameter(1, Type.INT);
- Local<T> localNewValue = code.getParameter(2, singleType);
- Local<T> localResult = code.newLocal(singleType);
- code.aget(localArray, localIndex, localResult);
- code.aput(localArray, localIndex, localNewValue);
- code.returnValue(localResult);
- return getMethod();
- }
-
- // TODO: fail if a label is unreachable (never navigated to)
-
- // TODO: more strict type parameters: Integer on methods
-
- // TODO: don't generate multiple times (?)
-
- private void addDefaultConstructor() {
- Code code = generator.declare(GENERATED.getConstructor(), ACC_PUBLIC | ACC_CONSTRUCTOR);
- Local<?> thisRef = code.getThis(GENERATED);
- code.invokeDirect(Type.OBJECT.getConstructor(), null, thisRef);
- code.returnVoid();
- }
-
- /**
- * Returns the generated method.
- */
- private Method getMethod() throws Exception {
- Class<?> generated = loadAndGenerate();
- for (Method method : generated.getMethods()) {
- if (method.getName().equals("call")) {
- return method;
- }
- }
- throw new IllegalStateException("no call() method");
- }
-
- 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;
- }
-
- private Class<?> loadAndGenerate() throws Exception {
- return generator.load(getClass().getClassLoader(),
- getDataDirectory(), getDataDirectory()).loadClass("Generated");
- }
-}
diff --git a/dx/junit-tests/com/android/dx/gen/ProxyBuilderTest.java b/dx/junit-tests/com/android/dx/gen/ProxyBuilderTest.java
deleted file mode 100644
index 070031cbc..000000000
--- a/dx/junit-tests/com/android/dx/gen/ProxyBuilderTest.java
+++ /dev/null
@@ -1,536 +0,0 @@
-/*
- * Copyright (C) 2011 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.android.dx.gen;
-
-import junit.framework.AssertionFailedError;
-import junit.framework.TestCase;
-
-import java.io.File;
-import java.io.IOException;
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.Method;
-import java.lang.reflect.UndeclaredThrowableException;
-import java.util.Random;
-
-public class ProxyBuilderTest extends TestCase {
- private FakeInvocationHandler fakeHandler = new FakeInvocationHandler();
-
- public static class SimpleClass {
- public String simpleMethod() {
- throw new AssertionFailedError();
- }
- }
-
- public void testExampleOperation() throws Throwable {
- fakeHandler.setFakeResult("expected");
- SimpleClass proxy = proxyFor(SimpleClass.class).build();
- assertEquals("expected", proxy.simpleMethod());
- }
-
- public static class ConstructorTakesArguments {
- private final String argument;
-
- public ConstructorTakesArguments(String arg) {
- argument = arg;
- }
-
- public String method() {
- throw new AssertionFailedError();
- }
- }
-
- public void testConstruction_SucceedsIfCorrectArgumentsProvided() throws Throwable {
- ConstructorTakesArguments proxy = proxyFor(ConstructorTakesArguments.class)
- .constructorArgTypes(String.class)
- .constructorArgValues("hello")
- .build();
- assertEquals("hello", proxy.argument);
- proxy.method();
- }
-
- public void testConstruction_FailsWithWrongNumberOfArguments() throws Throwable {
- try {
- proxyFor(ConstructorTakesArguments.class).build();
- fail();
- } catch (IllegalArgumentException expected) {}
- }
-
- public void testClassIsNotAccessbile_FailsWithUnsupportedOperationException() throws Exception {
- class MethodVisibilityClass {
- }
- try {
- proxyFor(MethodVisibilityClass.class).build();
- fail();
- } catch (UnsupportedOperationException expected) {}
- }
-
- private static class PrivateVisibilityClass {
- }
-
- public void testPrivateClass_FailsWithUnsupportedOperationException() throws Exception {
- try {
- proxyFor(PrivateVisibilityClass.class).build();
- fail();
- } catch (UnsupportedOperationException expected) {}
- }
-
- protected static class ProtectedVisibilityClass {
- public String foo() {
- throw new AssertionFailedError();
- }
- }
-
- public void testProtectedVisibility_WorksFine() throws Exception {
- assertEquals("fake result", proxyFor(ProtectedVisibilityClass.class).build().foo());
- }
-
- public static class HasFinalMethod {
- public String nonFinalMethod() {
- return "non-final method";
- }
-
- public final String finalMethod() {
- return "final method";
- }
- }
-
- public void testCanProxyClassesWithFinalMethods_WillNotCallTheFinalMethod() throws Throwable {
- HasFinalMethod proxy = proxyFor(HasFinalMethod.class).build();
- assertEquals("final method", proxy.finalMethod());
- assertEquals("fake result", proxy.nonFinalMethod());
- }
-
- public static class HasPrivateMethod {
- private String result() {
- return "expected";
- }
- }
-
- public void testProxyingPrivateMethods_NotIntercepted() throws Throwable {
- assertEquals("expected", proxyFor(HasPrivateMethod.class).build().result());
- }
-
- public static class HasPackagePrivateMethod {
- String result() {
- throw new AssertionFailedError();
- }
- }
-
- public void testProxyingPackagePrivateMethods_AreIntercepted() throws Throwable {
- assertEquals("fake result", proxyFor(HasPackagePrivateMethod.class).build().result());
- }
-
- public static class HasProtectedMethod {
- protected String result() {
- throw new AssertionFailedError();
- }
- }
-
- public void testProxyingProtectedMethods_AreIntercepted() throws Throwable {
- assertEquals("fake result", proxyFor(HasProtectedMethod.class).build().result());
- }
-
- public static class HasVoidMethod {
- public void dangerousMethod() {
- fail();
- }
- }
-
- public void testVoidMethod_ShouldNotThrowRuntimeException() throws Throwable {
- proxyFor(HasVoidMethod.class).build().dangerousMethod();
- }
-
- public void testObjectMethodsAreAlsoProxied() throws Throwable {
- Object proxy = proxyFor(Object.class).build();
- fakeHandler.setFakeResult("mystring");
- assertEquals("mystring", proxy.toString());
- fakeHandler.setFakeResult(-1);
- assertEquals(-1, proxy.hashCode());
- fakeHandler.setFakeResult(false);
- assertEquals(false, proxy.equals(proxy));
- }
-
- public static class AllPrimitiveMethods {
- public boolean getBoolean() { return true; }
- public int getInt() { return 1; }
- public byte getByte() { return 2; }
- public long getLong() { return 3L; }
- public short getShort() { return 4; }
- public float getFloat() { return 5f; }
- public double getDouble() { return 6.0; }
- public char getChar() { return 'c'; }
- }
-
- public void testAllPrimitiveReturnTypes() throws Throwable {
- AllPrimitiveMethods proxy = proxyFor(AllPrimitiveMethods.class).build();
- fakeHandler.setFakeResult(false);
- assertEquals(false, proxy.getBoolean());
- fakeHandler.setFakeResult(8);
- assertEquals(8, proxy.getInt());
- fakeHandler.setFakeResult((byte) 9);
- assertEquals(9, proxy.getByte());
- fakeHandler.setFakeResult(10L);
- assertEquals(10, proxy.getLong());
- fakeHandler.setFakeResult((short) 11);
- assertEquals(11, proxy.getShort());
- fakeHandler.setFakeResult(12f);
- assertEquals(12f, proxy.getFloat());
- fakeHandler.setFakeResult(13.0);
- assertEquals(13.0, proxy.getDouble());
- fakeHandler.setFakeResult('z');
- assertEquals('z', proxy.getChar());
- }
-
- public static class PassThroughAllPrimitives {
- public boolean getBoolean(boolean input) { return input; }
- public int getInt(int input) { return input; }
- public byte getByte(byte input) { return input; }
- public long getLong(long input) { return input; }
- public short getShort(short input) { return input; }
- public float getFloat(float input) { return input; }
- public double getDouble(double input) { return input; }
- public char getChar(char input) { return input; }
- public String getString(String input) { return input; }
- public Object getObject(Object input) { return input; }
- public void getNothing() {}
- }
-
- public static class InvokeSuperHandler implements InvocationHandler {
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- return ProxyBuilder.callSuper(proxy, method, args);
- }
- }
-
- public void testPassThroughWorksForAllPrimitives() throws Exception {
- PassThroughAllPrimitives proxy = proxyFor(PassThroughAllPrimitives.class)
- .handler(new InvokeSuperHandler())
- .build();
- assertEquals(false, proxy.getBoolean(false));
- assertEquals(true, proxy.getBoolean(true));
- assertEquals(0, proxy.getInt(0));
- assertEquals(1, proxy.getInt(1));
- assertEquals((byte) 2, proxy.getByte((byte) 2));
- assertEquals((byte) 3, proxy.getByte((byte) 3));
- assertEquals(4L, proxy.getLong(4L));
- assertEquals(5L, proxy.getLong(5L));
- assertEquals((short) 6, proxy.getShort((short) 6));
- assertEquals((short) 7, proxy.getShort((short) 7));
- assertEquals(8f, proxy.getFloat(8f));
- assertEquals(9f, proxy.getFloat(9f));
- assertEquals(10.0, proxy.getDouble(10.0));
- assertEquals(11.0, proxy.getDouble(11.0));
- assertEquals('a', proxy.getChar('a'));
- assertEquals('b', proxy.getChar('b'));
- assertEquals("asdf", proxy.getString("asdf"));
- assertEquals("qwer", proxy.getString("qwer"));
- assertEquals(null, proxy.getString(null));
- Object a = new Object();
- assertEquals(a, proxy.getObject(a));
- assertEquals(null, proxy.getObject(null));
- proxy.getNothing();
- }
-
- public static class ExtendsAllPrimitiveMethods extends AllPrimitiveMethods {
- public int example() { return 0; }
- }
-
- public void testProxyWorksForSuperclassMethodsAlso() throws Throwable {
- ExtendsAllPrimitiveMethods proxy = proxyFor(ExtendsAllPrimitiveMethods.class).build();
- fakeHandler.setFakeResult(99);
- assertEquals(99, proxy.example());
- assertEquals(99, proxy.getInt());
- assertEquals(99, proxy.hashCode());
- }
-
- public static class HasOddParams {
- public long method(int first, Integer second) {
- throw new AssertionFailedError();
- }
- }
-
- public void testMixingBoxedAndUnboxedParams() throws Throwable {
- HasOddParams proxy = proxyFor(HasOddParams.class).build();
- fakeHandler.setFakeResult(99L);
- assertEquals(99L, proxy.method(1, Integer.valueOf(2)));
- }
-
- public static class SingleInt {
- public String getString(int value) {
- throw new AssertionFailedError();
- }
- }
-
- public void testSinglePrimitiveParameter() throws Throwable {
- InvocationHandler handler = new InvocationHandler() {
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- return "asdf" + ((Integer) args[0]).intValue();
- }
- };
- assertEquals("asdf1", proxyFor(SingleInt.class).handler(handler).build().getString(1));
- }
-
- public static class TwoConstructors {
- private final String string;
-
- public TwoConstructors() {
- string = "no-arg";
- }
-
- public TwoConstructors(boolean unused) {
- string = "one-arg";
- }
- }
-
- public void testNoConstructorArguments_CallsNoArgConstructor() throws Throwable {
- TwoConstructors twoConstructors = proxyFor(TwoConstructors.class).build();
- assertEquals("no-arg", twoConstructors.string);
- }
-
- public void testWithoutInvocationHandler_ThrowsIllegalArgumentException() throws Throwable {
- try {
- ProxyBuilder.forClass(TwoConstructors.class)
- .dexCache(DexGeneratorTest.getDataDirectory())
- .build();
- fail();
- } catch (IllegalArgumentException expected) {}
- }
-
- public static class HardToConstructCorrectly {
- public HardToConstructCorrectly() { fail(); }
- public HardToConstructCorrectly(Runnable ignored) { fail(); }
- public HardToConstructCorrectly(Exception ignored) { fail(); }
- public HardToConstructCorrectly(Boolean ignored) { /* safe */ }
- public HardToConstructCorrectly(Integer ignored) { fail(); }
- }
-
- public void testHardToConstruct_WorksIfYouSpecifyTheConstructorCorrectly() throws Throwable {
- proxyFor(HardToConstructCorrectly.class)
- .constructorArgTypes(Boolean.class)
- .constructorArgValues(true)
- .build();
- }
-
- public void testHardToConstruct_EvenWorksWhenArgsAreAmbiguous() throws Throwable {
- proxyFor(HardToConstructCorrectly.class)
- .constructorArgTypes(Boolean.class)
- .constructorArgValues(new Object[] { null })
- .build();
- }
-
- public void testHardToConstruct_DoesNotInferTypesFromValues() throws Throwable {
- try {
- proxyFor(HardToConstructCorrectly.class)
- .constructorArgValues(true)
- .build();
- fail();
- } catch (IllegalArgumentException expected) {}
- }
-
- public void testDefaultProxyHasSuperMethodToAccessOriginal() throws Exception {
- Object objectProxy = proxyFor(Object.class).build();
- assertNotNull(objectProxy.getClass().getMethod("super_hashCode"));
- }
-
- public static class PrintsOddAndValue {
- public String method(int value) {
- return "odd " + value;
- }
- }
-
- public void testSometimesDelegateToSuper() throws Exception {
- InvocationHandler delegatesOddValues = new InvocationHandler() {
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- if (method.getName().equals("method")) {
- int intValue = ((Integer) args[0]).intValue();
- if (intValue % 2 == 0) {
- return "even " + intValue;
- }
- }
- return ProxyBuilder.callSuper(proxy, method, args);
- }
- };
- PrintsOddAndValue proxy = proxyFor(PrintsOddAndValue.class)
- .handler(delegatesOddValues)
- .build();
- assertEquals("even 0", proxy.method(0));
- assertEquals("odd 1", proxy.method(1));
- assertEquals("even 2", proxy.method(2));
- assertEquals("odd 3", proxy.method(3));
- }
-
- public static class DoubleReturn {
- public double getValue() {
- return 2.0;
- }
- }
-
- public void testUnboxedResult() throws Exception {
- fakeHandler.fakeResult = 2.0;
- assertEquals(2.0, proxyFor(DoubleReturn.class).build().getValue());
- }
-
- public static void staticMethod() {
- }
-
- public void testDoesNotOverrideStaticMethods() throws Exception {
- // Method should exist on this test class itself.
- ProxyBuilderTest.class.getDeclaredMethod("staticMethod");
- // Method should not exist on the subclass.
- try {
- proxyFor(ProxyBuilderTest.class).build().getClass().getDeclaredMethod("staticMethod");
- fail();
- } catch (NoSuchMethodException expected) {}
- }
-
- public void testIllegalCacheDirectory() throws Exception {
- try {
- proxyFor(Object.class).dexCache(new File("//////")).build();
- fail();
- } catch (DexCacheException expected) {}
- }
-
- public void testInvalidConstructorSpecification() throws Exception {
- try {
- proxyFor(Object.class)
- .constructorArgTypes(String.class, Boolean.class)
- .constructorArgValues("asdf", true)
- .build();
- fail();
- } catch (IllegalArgumentException expected) {}
- }
-
- public static abstract class AbstractClass {
- public abstract Object getValue();
- }
-
- public void testAbstractClassBehaviour() throws Exception {
- assertEquals("fake result", proxyFor(AbstractClass.class).build().getValue());
- }
-
- public static class CtorHasDeclaredException {
- public CtorHasDeclaredException() throws IOException {
- throw new IOException();
- }
- }
-
- public static class CtorHasRuntimeException {
- public CtorHasRuntimeException() {
- throw new RuntimeException("my message");
- }
- }
-
- public static class CtorHasError {
- public CtorHasError() {
- throw new Error("my message again");
- }
- }
-
- public void testParentConstructorThrowsDeclaredException() throws Exception {
- try {
- proxyFor(CtorHasDeclaredException.class).build();
- fail();
- } catch (UndeclaredThrowableException expected) {
- assertTrue(expected.getCause() instanceof IOException);
- }
- try {
- proxyFor(CtorHasRuntimeException.class).build();
- fail();
- } catch (RuntimeException expected) {
- assertEquals("my message", expected.getMessage());
- }
- try {
- proxyFor(CtorHasError.class).build();
- fail();
- } catch (Error expected) {
- assertEquals("my message again", expected.getMessage());
- }
- }
-
- public void testGetInvocationHandler_NormalOperation() throws Exception {
- Object proxy = proxyFor(Object.class).build();
- assertSame(fakeHandler, ProxyBuilder.getInvocationHandler(proxy));
- }
-
- public void testGetInvocationHandler_NotAProxy() {
- try {
- ProxyBuilder.getInvocationHandler(new Object());
- fail();
- } catch (IllegalArgumentException expected) {}
- }
-
- public static class ReturnsObject {
- public Object getValue() {
- return new Object();
- }
- }
-
- public static class ReturnsString extends ReturnsObject {
- @Override
- public String getValue() {
- return "a string";
- }
- }
-
- public void testCovariantReturnTypes_NormalBehaviour() throws Exception {
- String expected = "some string";
- fakeHandler.setFakeResult(expected);
- assertSame(expected, proxyFor(ReturnsObject.class).build().getValue());
- assertSame(expected, proxyFor(ReturnsString.class).build().getValue());
- }
-
- public void testCovariantReturnTypes_WrongReturnType() throws Exception {
- try {
- fakeHandler.setFakeResult(new Object());
- proxyFor(ReturnsString.class).build().getValue();
- fail();
- } catch (ClassCastException expected) {}
- }
-
- public void testCaching_ShouldWork() {
- // TODO: We're not supporting caching yet. But we should as soon as possible.
- fail();
- }
-
- public void testSubclassOfRandom() throws Exception {
- proxyFor(Random.class)
- .handler(new InvokeSuperHandler())
- .build();
- }
-
- /** Simple helper to add the most common args for this test to the proxy builder. */
- private <T> ProxyBuilder<T> proxyFor(Class<T> clazz) throws Exception {
- return ProxyBuilder.forClass(clazz)
- .handler(fakeHandler)
- .dexCache(DexGeneratorTest.getDataDirectory());
- }
-
- private static class FakeInvocationHandler implements InvocationHandler {
- private Object fakeResult = "fake result";
-
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- return fakeResult;
- }
-
- public void setFakeResult(Object result) {
- fakeResult = result;
- }
- }
-}
diff --git a/dx/junit-tests/com/android/dx/gen/TypeTest.java b/dx/junit-tests/com/android/dx/gen/TypeTest.java
deleted file mode 100644
index a7e17e8cf..000000000
--- a/dx/junit-tests/com/android/dx/gen/TypeTest.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2011 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.android.dx.gen;
-
-import junit.framework.TestCase;
-
-public final class TypeTest 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());
- }
-}
diff --git a/dx/src/com/android/dx/gen/BinaryOp.java b/dx/src/com/android/dx/gen/BinaryOp.java
deleted file mode 100644
index 65a29983a..000000000
--- a/dx/src/com/android/dx/gen/BinaryOp.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2011 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.android.dx.gen;
-
-import com.android.dx.rop.code.Rop;
-import com.android.dx.rop.code.Rops;
-import com.android.dx.rop.type.TypeList;
-
-/**
- * An operation on two values of the same type.
- *
- * <p>Math operations ({@link #ADD}, {@link #SUBTRACT}, {@link #MULTIPLY},
- * {@link #DIVIDE}, and {@link #REMAINDER}) support ints, longs, floats and
- * doubles.
- *
- * <p>Bit operations ({@link #AND}, {@link #OR}, {@link #XOR}, {@link
- * #SHIFT_LEFT}, {@link #SHIFT_RIGHT}, {@link #UNSIGNED_SHIFT_RIGHT}) support
- * ints and longs.
- *
- * <p>Division by zero behaves differently depending on the operand type.
- * For int and long operands, {@link #DIVIDE} and {@link #REMAINDER} throw
- * {@link ArithmeticException} if {@code b == 0}. For float and double operands,
- * the operations return {@code NaN}.
- */
-public enum BinaryOp {
- /** {@code a + b} */
- ADD() {
- @Override Rop rop(TypeList types) {
- return Rops.opAdd(types);
- }
- },
-
- /** {@code a - b} */
- SUBTRACT() {
- @Override Rop rop(TypeList types) {
- return Rops.opSub(types);
- }
- },
-
- /** {@code a * b} */
- MULTIPLY() {
- @Override Rop rop(TypeList types) {
- return Rops.opMul(types);
- }
- },
-
- /** {@code a / b} */
- DIVIDE() {
- @Override Rop rop(TypeList types) {
- return Rops.opDiv(types);
- }
- },
-
- /** {@code a % b} */
- REMAINDER() {
- @Override Rop rop(TypeList types) {
- return Rops.opRem(types);
- }
- },
-
- /** {@code a & b} */
- AND() {
- @Override Rop rop(TypeList types) {
- return Rops.opAnd(types);
- }
- },
-
- /** {@code a | b} */
- OR() {
- @Override Rop rop(TypeList types) {
- return Rops.opOr(types);
- }
- },
-
- /** {@code a ^ b} */
- XOR() {
- @Override Rop rop(TypeList types) {
- return Rops.opXor(types);
- }
- },
-
- /** {@code a << b} */
- SHIFT_LEFT() {
- @Override Rop rop(TypeList types) {
- return Rops.opShl(types);
- }
- },
-
- /** {@code a >> b} */
- SHIFT_RIGHT() {
- @Override Rop rop(TypeList types) {
- return Rops.opShr(types);
- }
- },
-
- /** {@code a >>> b} */
- UNSIGNED_SHIFT_RIGHT() {
- @Override Rop rop(TypeList types) {
- return Rops.opUshr(types);
- }
- };
-
- abstract Rop rop(com.android.dx.rop.type.TypeList types);
-}
diff --git a/dx/src/com/android/dx/gen/Code.java b/dx/src/com/android/dx/gen/Code.java
deleted file mode 100644
index 3868cd3b5..000000000
--- a/dx/src/com/android/dx/gen/Code.java
+++ /dev/null
@@ -1,570 +0,0 @@
-/*
- * Copyright (C) 2011 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.android.dx.gen;
-
-import com.android.dx.rop.code.BasicBlockList;
-import com.android.dx.rop.code.Insn;
-import com.android.dx.rop.code.PlainCstInsn;
-import com.android.dx.rop.code.PlainInsn;
-import com.android.dx.rop.code.RegisterSpecList;
-import com.android.dx.rop.code.Rop;
-import static com.android.dx.rop.code.Rop.BRANCH_GOTO;
-import static com.android.dx.rop.code.Rop.BRANCH_NONE;
-import static com.android.dx.rop.code.Rop.BRANCH_RETURN;
-import com.android.dx.rop.code.Rops;
-import com.android.dx.rop.code.SourcePosition;
-import com.android.dx.rop.code.ThrowingCstInsn;
-import com.android.dx.rop.code.ThrowingInsn;
-import com.android.dx.rop.cst.CstInteger;
-import com.android.dx.rop.type.StdTypeList;
-import static com.android.dx.rop.type.Type.BT_BYTE;
-import static com.android.dx.rop.type.Type.BT_CHAR;
-import static com.android.dx.rop.type.Type.BT_INT;
-import static com.android.dx.rop.type.Type.BT_SHORT;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-
-/**
- * Builds a sequence of instructions.
- */
-public final class Code {
- private final MethodId<?, ?> method;
- /**
- * All allocated labels. Although the order of the labels in this list
- * shouldn't impact behavior, it is used to determine basic block indices.
- */
- private final List<Label> labels = new ArrayList<Label>();
-
- /**
- * The label currently receiving instructions. This is null if the most
- * recent instruction was a return or goto.
- */
- private Label currentLabel;
-
- /** true once we've fixed the positions of the parameter registers */
- private boolean localsInitialized;
-
- private final Local<?> thisLocal;
- 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<Label> catchLabels = new ArrayList<Label>();
- private StdTypeList catches = StdTypeList.EMPTY;
-
- Code(DexGenerator.MethodDeclaration methodDeclaration) {
- this.method = methodDeclaration.method;
- this.thisLocal = methodDeclaration.isStatic()
- ? null
- : Local.get(this, method.declaringType);
- for (Type<?> 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) {
- if (localsInitialized) {
- throw new IllegalStateException("Cannot allocate locals after adding instructions");
- }
- Local<T> result = Local.get(this, type);
- locals.add(result);
- return result;
- }
-
- public <T> Local<T> getParameter(int index, Type<T> type) {
- return coerce(parameters.get(index), type);
- }
-
- public <T> Local<T> getThis(Type<T> type) {
- if (thisLocal == null) {
- throw new IllegalStateException("static methods cannot access 'this'");
- }
- return coerce(thisLocal, type);
- }
-
- @SuppressWarnings("unchecked") // guarded by an equals check
- private <T> Local<T> coerce(Local<?> local, Type<T> expectedType) {
- if (!local.type.equals(expectedType)) {
- throw new IllegalArgumentException(
- "requested " + expectedType + " but was " + local.type);
- }
- return (Local<T>) local;
- }
-
- /**
- * Assigns registers to locals. From the spec:
- * "the N arguments to a method land in the last N registers of the
- * method's invocation frame, in order. Wide arguments consume two
- * registers. Instance methods are passed a this reference as their
- * first argument."
- *
- * In addition to assigning registers to each of the locals, this creates
- * instructions to move parameters into their initial registers. These
- * instructions are inserted before the code's first real instruction.
- */
- void initializeLocals() {
- if (localsInitialized) {
- throw new AssertionError();
- }
- localsInitialized = true;
-
- int reg = 0;
- for (Local<?> local : locals) {
- reg += local.initialize(reg);
- }
- if (thisLocal != null) {
- reg += thisLocal.initialize(reg);
- }
- int firstParamReg = reg;
-
- List<Insn> moveParameterInstructions = new ArrayList<Insn>();
- for (Local<?> local : parameters) {
- CstInteger paramConstant = CstInteger.make(reg - firstParamReg);
- reg += local.initialize(reg);
- moveParameterInstructions.add(new PlainCstInsn(Rops.opMoveParam(local.type.ropType),
- sourcePosition, local.spec(), RegisterSpecList.EMPTY, paramConstant));
- }
- labels.get(0).instructions.addAll(0, moveParameterInstructions);
- }
-
- int paramSize() {
- int result = 0;
- for (Local<?> local : parameters) {
- result += local.size();
- }
- return result;
- }
-
- // labels
-
- /**
- * Creates a new label for use as a branch target. The new label must have
- * code attached to it later by calling {@link #mark(Label)}.
- */
- public Label newLabel() {
- Label result = new Label();
- labels.add(result);
- return result;
- }
-
- /**
- * Start defining instructions for the named label.
- */
- public void mark(Label label) {
- if (label.marked) {
- throw new IllegalStateException("already marked");
- }
- label.marked = true;
- if (currentLabel != null) {
- jump(label); // blocks must end with a branch, return or throw
- }
- currentLabel = label;
- }
-
- public void jump(Label target) {
- addInstruction(new PlainInsn(Rops.GOTO, sourcePosition, null, RegisterSpecList.EMPTY),
- target);
- }
-
- public void addCatchClause(Type<?> throwable, Label catchClause) {
- if (catchTypes.contains(throwable)) {
- throw new IllegalArgumentException("Already caught: " + throwable);
- }
- catchTypes.add(throwable);
- catches = toTypeList(catchTypes);
- catchLabels.add(catchClause);
- }
-
- public Label removeCatchClause(Type<?> throwable) {
- int index = catchTypes.indexOf(throwable);
- if (index == -1) {
- throw new IllegalArgumentException("No catch clause: " + throwable);
- }
- catchTypes.remove(index);
- catches = toTypeList(catchTypes);
- return catchLabels.remove(index);
- }
-
- public void throwValue(Local<?> throwable) {
- addInstruction(new ThrowingInsn(Rops.THROW, sourcePosition,
- RegisterSpecList.make(throwable.spec()), catches));
- }
-
- private StdTypeList toTypeList(List<Type<?>> types) {
- StdTypeList result = new StdTypeList(types.size());
- for (int i = 0; i < types.size(); i++) {
- result.set(i, types.get(i).ropType);
- }
- return result;
- }
-
- private void addInstruction(Insn insn) {
- addInstruction(insn, null);
- }
-
- /**
- * @param branch the branches to follow; interpretation depends on the
- * instruction's branchingness.
- */
- private void addInstruction(Insn insn, Label branch) {
- if (currentLabel == null || !currentLabel.marked) {
- throw new IllegalStateException("no current label");
- }
- currentLabel.instructions.add(insn);
-
- switch (insn.getOpcode().getBranchingness()) {
- case BRANCH_NONE:
- if (branch != null) {
- throw new IllegalArgumentException("unexpected branch: " + branch);
- }
- return;
-
- case BRANCH_RETURN:
- if (branch != null) {
- throw new IllegalArgumentException("unexpected branch: " + branch);
- }
- currentLabel = null;
- break;
-
- case BRANCH_GOTO:
- if (branch == null) {
- throw new IllegalArgumentException("branch == null");
- }
- currentLabel.primarySuccessor = branch;
- currentLabel = null;
- break;
-
- case Rop.BRANCH_IF:
- if (branch == null) {
- throw new IllegalArgumentException("branch == null");
- }
- splitCurrentLabel(branch, Collections.<Label>emptyList());
- break;
-
- case Rop.BRANCH_THROW:
- if (branch != null) {
- throw new IllegalArgumentException("unexpected branch: " + branch);
- }
- splitCurrentLabel(null, new ArrayList<Label>(catchLabels));
- break;
-
- default:
- throw new IllegalArgumentException();
- }
- }
-
- /**
- * Closes the current label and starts a new one.
- *
- * @param catchLabels an immutable list of catch labels
- */
- private void splitCurrentLabel(Label alternateSuccessor, List<Label> catchLabels) {
- Label newLabel = newLabel();
- currentLabel.primarySuccessor = newLabel;
- currentLabel.alternateSuccessor = alternateSuccessor;
- currentLabel.catchLabels = catchLabels;
- currentLabel = newLabel;
- currentLabel.marked = true;
- }
-
- // instructions: constants
-
- public <T> void loadConstant(Local<T> target, T value) {
- Rop rop = value == null
- ? Rops.CONST_OBJECT_NOTHROW
- : Rops.opConst(target.type.ropType);
- if (rop.getBranchingness() == BRANCH_NONE) {
- addInstruction(new PlainCstInsn(rop, sourcePosition, target.spec(),
- RegisterSpecList.EMPTY, Constants.getConstant(value)));
- } else {
- addInstruction(new ThrowingCstInsn(rop, sourcePosition,
- RegisterSpecList.EMPTY, catches, Constants.getConstant(value)));
- moveResult(target, true);
- }
- }
-
- // instructions: unary
-
- public <T> void negate(Local<T> source, Local<T> target) {
- unary(Rops.opNeg(source.type.ropType), source, target);
- }
-
- public <T> void not(Local<T> source, Local<T> target) {
- unary(Rops.opNot(source.type.ropType), source, target);
- }
-
- public void numericCast(Local<?> source, Local<?> target) {
- unary(getCastRop(source.type.ropType, target.type.ropType), source, target);
- }
-
- private Rop getCastRop(com.android.dx.rop.type.Type sourceType,
- com.android.dx.rop.type.Type targetType) {
- if (sourceType.getBasicType() == BT_INT) {
- switch (targetType.getBasicType()) {
- case BT_SHORT:
- return Rops.TO_SHORT;
- case BT_CHAR:
- return Rops.TO_CHAR;
- case BT_BYTE:
- return Rops.TO_BYTE;
- }
- }
- return Rops.opConv(targetType, sourceType);
- }
-
- private void unary(Rop rop, Local<?> source, Local<?> target) {
- addInstruction(new PlainInsn(rop, sourcePosition, target.spec(), source.spec()));
- }
-
- // instructions: binary
-
- public <T> void op(BinaryOp op, Local<T> target, Local<T> a, Local<T> b) {
- Rop rop = op.rop(StdTypeList.make(a.type.ropType, b.type.ropType));
- RegisterSpecList sources = RegisterSpecList.make(a.spec(), b.spec());
-
- if (rop.getBranchingness() == BRANCH_NONE) {
- addInstruction(new PlainInsn(rop, sourcePosition, target.spec(), sources));
- } else {
- addInstruction(new ThrowingInsn(rop, sourcePosition, sources, catches));
- moveResult(target, true);
- }
- }
-
- // instructions: branches
-
- /**
- * 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) {
- if (trueLabel == null) {
- throw new IllegalArgumentException();
- }
- Rop rop = comparison.rop(StdTypeList.make(a.type.ropType, b.type.ropType));
- addInstruction(new PlainInsn(rop, sourcePosition, null,
- RegisterSpecList.make(a.spec(), b.spec())), trueLabel);
- }
-
- /**
- * Compare floats or doubles.
- */
- public <T extends Number> void compare(Local<T> a, Local<T> b, Local<Integer> target,
- int nanValue) {
- Rop rop;
- if (nanValue == 1) {
- rop = Rops.opCmpg(a.type.ropType);
- } else if (nanValue == -1) {
- rop = Rops.opCmpl(a.type.ropType);
- } else {
- throw new IllegalArgumentException("expected 1 or -1 but was " + nanValue);
- }
- addInstruction(new PlainInsn(rop, sourcePosition, target.spec(),
- RegisterSpecList.make(a.spec(), b.spec())));
- }
-
- /**
- * Compare longs.
- */
- public <T> void compare(Local<T> a, Local<T> b, Local<?> target) {
- 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) {
- addInstruction(new ThrowingCstInsn(Rops.opGetField(target.type.ropType), sourcePosition,
- RegisterSpecList.make(instance.spec()), catches, fieldId.constant));
- moveResult(target, true);
- }
-
- public <D, V> void iput(FieldId<D, V> fieldId, Local<D> instance, Local<V> source) {
- addInstruction(new ThrowingCstInsn(Rops.opPutField(source.type.ropType), sourcePosition,
- RegisterSpecList.make(source.spec(), instance.spec()), catches, fieldId.constant));
- }
-
- public <V> void sget(FieldId<?, V> fieldId, Local<V> target) {
- addInstruction(new ThrowingCstInsn(Rops.opGetStatic(target.type.ropType), sourcePosition,
- RegisterSpecList.EMPTY, catches, fieldId.constant));
- moveResult(target, true);
- }
-
- public <V> void sput(FieldId<?, V> fieldId, Local<V> source) {
- addInstruction(new ThrowingCstInsn(Rops.opPutStatic(source.type.ropType), sourcePosition,
- RegisterSpecList.make(source.spec()), catches, fieldId.constant));
- }
-
- // instructions: invoke
-
- public <T> void newInstance(Local<T> target, MethodId<T, Void> constructor, Local<?>... args) {
- if (target == null) {
- throw new IllegalArgumentException();
- }
- addInstruction(new ThrowingCstInsn(Rops.NEW_INSTANCE, sourcePosition,
- RegisterSpecList.EMPTY, catches, constructor.declaringType.constant));
- moveResult(target, true);
- invokeDirect(constructor, null, target, args);
- }
-
- public <R> void invokeStatic(MethodId<?, R> method, Local<? super R> target, Local<?>... args) {
- invoke(Rops.opInvokeStatic(method.prototype(true)), method, target, null, args);
- }
-
- public <D, R> void invokeVirtual(MethodId<D, R> method, Local<? super R> target,
- Local<? extends D> object, Local<?>... args) {
- invoke(Rops.opInvokeVirtual(method.prototype(true)), method, target, object, args);
- }
-
- public <D, R> void invokeDirect(MethodId<D, R> method, Local<? super R> target,
- Local<? extends D> object, Local<?>... args) {
- invoke(Rops.opInvokeDirect(method.prototype(true)), method, target, object, args);
- }
-
- public <D, R> void invokeSuper(MethodId<D, R> method, Local<? super R> target,
- Local<? extends D> object, Local<?>... args) {
- invoke(Rops.opInvokeSuper(method.prototype(true)), method, target, object, args);
- }
-
- public <D, R> void invokeInterface(MethodId<D, R> method, Local<? super R> target,
- Local<? extends D> object, Local<?>... args) {
- invoke(Rops.opInvokeInterface(method.prototype(true)), method, target, object, args);
- }
-
- private <D, R> void invoke(Rop rop, MethodId<D, R> method, Local<? super R> target,
- Local<? extends D> object, Local<?>... args) {
- addInstruction(new ThrowingCstInsn(rop, sourcePosition, concatenate(object, args),
- catches, method.constant));
- if (target != null) {
- moveResult(target, false);
- }
- }
-
- // instructions: types
-
- public void instanceOfType(Local<?> target, Local<?> source, Type<?> 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) {
- addInstruction(new ThrowingCstInsn(Rops.CHECK_CAST, sourcePosition,
- RegisterSpecList.make(source.spec()), catches, target.type.constant));
- moveResult(target, true);
- }
-
- // instructions: arrays
-
- public <T> void arrayLength(Local<T> array, Local<Integer> target) {
- 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) {
- 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) {
- addInstruction(new ThrowingInsn(Rops.opAget(target.type.ropType), sourcePosition,
- RegisterSpecList.make(array.spec(), index.spec()), catches));
- moveResult(target, true);
- }
-
- public void aput(Local<?> array, Local<Integer> index, Local<?> source) {
- addInstruction(new ThrowingInsn(Rops.opAput(source.type.ropType), sourcePosition,
- RegisterSpecList.make(source.spec(), array.spec(), index.spec()), catches));
- }
-
- // instructions: return
-
- public void returnVoid() {
- if (!method.returnType.equals(Type.VOID)) {
- throw new IllegalArgumentException("declared " + method.returnType
- + " but returned void");
- }
- addInstruction(new PlainInsn(Rops.RETURN_VOID, sourcePosition, null,
- RegisterSpecList.EMPTY));
- }
-
- public void returnValue(Local<?> result) {
- if (!result.type.equals(method.returnType)) {
- // TODO: this is probably too strict.
- throw new IllegalArgumentException("declared " + method.returnType
- + " but returned " + result.type);
- }
- addInstruction(new PlainInsn(Rops.opReturn(result.type.ropType), sourcePosition,
- null, RegisterSpecList.make(result.spec())));
- }
-
- private void moveResult(Local<?> target, boolean afterNonInvokeThrowingInsn) {
- Rop rop = afterNonInvokeThrowingInsn
- ? Rops.opMoveResultPseudo(target.type.ropType)
- : Rops.opMoveResult(target.type.ropType);
- addInstruction(new PlainInsn(rop, sourcePosition, target.spec(), RegisterSpecList.EMPTY));
- }
-
- // produce BasicBlocks for dex
-
- BasicBlockList toBasicBlocks() {
- if (!localsInitialized) {
- initializeLocals();
- }
-
- cleanUpLabels();
-
- BasicBlockList result = new BasicBlockList(labels.size());
- for (int i = 0; i < labels.size(); i++) {
- result.set(i, labels.get(i).toBasicBlock());
- }
- return result;
- }
-
- /**
- * Removes empty labels and assigns IDs to non-empty labels.
- */
- private void cleanUpLabels() {
- int id = 0;
- for (Iterator<Label> i = labels.iterator(); i.hasNext();) {
- Label label = i.next();
- if (label.isEmpty()) {
- i.remove();
- } else {
- label.compact();
- label.id = id++;
- }
- }
- }
-
- private static RegisterSpecList concatenate(Local<?> first, Local<?>[] rest) {
- int offset = (first != null) ? 1 : 0;
- RegisterSpecList result = new RegisterSpecList(offset + rest.length);
- if (first != null) {
- result.set(0, first.spec());
- }
- for (int i = 0; i < rest.length; i++) {
- result.set(i + offset, rest[i].spec());
- }
- return result;
- }
-}
diff --git a/dx/src/com/android/dx/gen/Comparison.java b/dx/src/com/android/dx/gen/Comparison.java
deleted file mode 100644
index 40a6e9724..000000000
--- a/dx/src/com/android/dx/gen/Comparison.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2011 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.android.dx.gen;
-
-import com.android.dx.rop.code.Rop;
-import com.android.dx.rop.code.Rops;
-import com.android.dx.rop.type.TypeList;
-
-/**
- * A comparison between two values of the same type.
- */
-public enum Comparison {
-
- /** {@code a < b} */
- LT() {
- @Override Rop rop(TypeList types) {
- return Rops.opIfLt(types);
- }
- },
-
- /** {@code a <= b} */
- LE() {
- @Override Rop rop(TypeList types) {
- return Rops.opIfLe(types);
- }
- },
-
- /** {@code a == b} */
- EQ() {
- @Override Rop rop(TypeList types) {
- return Rops.opIfEq(types);
- }
- },
-
- /** {@code a >= b} */
- GE() {
- @Override Rop rop(TypeList types) {
- return Rops.opIfGe(types);
- }
- },
-
- /** {@code a > b} */
- GT() {
- @Override Rop rop(TypeList types) {
- return Rops.opIfGt(types);
- }
- },
-
- /** {@code a != b} */
- NE() {
- @Override Rop rop(TypeList types) {
- return Rops.opIfNe(types);
- }
- };
-
- abstract Rop rop(TypeList types);
-}
diff --git a/dx/src/com/android/dx/gen/Constants.java b/dx/src/com/android/dx/gen/Constants.java
deleted file mode 100644
index 255c2e4ce..000000000
--- a/dx/src/com/android/dx/gen/Constants.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2011 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.android.dx.gen;
-
-import com.android.dx.rop.cst.CstBoolean;
-import com.android.dx.rop.cst.CstByte;
-import com.android.dx.rop.cst.CstChar;
-import com.android.dx.rop.cst.CstDouble;
-import com.android.dx.rop.cst.CstFloat;
-import com.android.dx.rop.cst.CstInteger;
-import com.android.dx.rop.cst.CstKnownNull;
-import com.android.dx.rop.cst.CstLong;
-import com.android.dx.rop.cst.CstShort;
-import com.android.dx.rop.cst.CstString;
-import com.android.dx.rop.cst.CstType;
-import com.android.dx.rop.cst.TypedConstant;
-
-/**
- * Factory for rop constants.
- */
-final class Constants {
- private Constants() {}
-
- /**
- * Returns a rop constant for the specified value.
- *
- * @param value null, a boxed primitive, String, Class, or Type.
- */
- static TypedConstant getConstant(Object value) {
- if (value == null) {
- return CstKnownNull.THE_ONE;
- } else if (value instanceof Boolean) {
- return CstBoolean.make((Boolean) value);
- } else if (value instanceof Byte) {
- return CstByte.make((Byte) value);
- } else if (value instanceof Character) {
- return CstChar.make((Character) value);
- } else if (value instanceof Double) {
- return CstDouble.make(Double.doubleToLongBits((Double) value));
- } else if (value instanceof Float) {
- return CstFloat.make(Float.floatToIntBits((Float) value));
- } else if (value instanceof Integer) {
- return CstInteger.make((Integer) value);
- } else if (value instanceof Long) {
- return CstLong.make((Long) value);
- } else if (value instanceof Short) {
- return CstShort.make((Short) value);
- } 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);
- } else {
- throw new UnsupportedOperationException("Not a constant: " + value);
- }
- }
-}
diff --git a/dx/src/com/android/dx/gen/DexCacheException.java b/dx/src/com/android/dx/gen/DexCacheException.java
deleted file mode 100644
index 560844098..000000000
--- a/dx/src/com/android/dx/gen/DexCacheException.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2011 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.android.dx.gen;
-
-import java.io.IOException;
-
-/** Thrown when there is an IOException when writing to the dex cache directory. */
-public final class DexCacheException extends RuntimeException {
- private static final long serialVersionUID = 0L;
-
- public DexCacheException(IOException cause) {
- super(cause);
- }
-}
diff --git a/dx/src/com/android/dx/gen/DexGenerator.java b/dx/src/com/android/dx/gen/DexGenerator.java
deleted file mode 100644
index 56c516b0c..000000000
--- a/dx/src/com/android/dx/gen/DexGenerator.java
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * Copyright (C) 2011 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.android.dx.gen;
-
-import static com.android.dx.rop.code.AccessFlags.ACC_CONSTRUCTOR;
-import static com.android.dx.rop.code.AccessFlags.ACC_PRIVATE;
-import static com.android.dx.rop.code.AccessFlags.ACC_STATIC;
-
-import com.android.dx.dex.DexFormat;
-import com.android.dx.dex.DexOptions;
-import com.android.dx.dex.code.DalvCode;
-import com.android.dx.dex.code.PositionList;
-import com.android.dx.dex.code.RopTranslator;
-import com.android.dx.dex.file.ClassDefItem;
-import com.android.dx.dex.file.DexFile;
-import com.android.dx.dex.file.EncodedField;
-import com.android.dx.dex.file.EncodedMethod;
-import com.android.dx.rop.code.AccessFlags;
-import com.android.dx.rop.code.LocalVariableInfo;
-import com.android.dx.rop.code.RopMethod;
-import com.android.dx.rop.cst.CstString;
-import com.android.dx.rop.cst.CstType;
-import com.android.dx.rop.type.StdTypeList;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.lang.reflect.InvocationTargetException;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.jar.JarEntry;
-import java.util.jar.JarOutputStream;
-
-/**
- * Define types, fields and methods.
- */
-public final class DexGenerator {
- private final Map<Type<?>, TypeDeclaration> types
- = new LinkedHashMap<Type<?>, TypeDeclaration>();
-
- private TypeDeclaration getTypeDeclaration(Type<?> type) {
- TypeDeclaration result = types.get(type);
- if (result == null) {
- result = new TypeDeclaration(type);
- types.put(type, result);
- }
- return result;
- }
-
- /**
- * @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) {
- TypeDeclaration declaration = getTypeDeclaration(type);
- if (declaration.declared) {
- throw new IllegalStateException("already declared: " + type);
- }
- declaration.declared = true;
- declaration.flags = flags;
- declaration.supertype = supertype;
- declaration.sourceFile = sourceFile;
- declaration.interfaces = new TypeList(interfaces);
- }
-
- /**
- * @param flags any flags masked by {@link com.android.dx.rop.code.AccessFlags#METHOD_FLAGS}.
- */
- public Code declare(MethodId<?, ?> method, int flags) {
- TypeDeclaration typeDeclaration = getTypeDeclaration(method.declaringType);
- if (typeDeclaration.methods.containsKey(method)) {
- throw new IllegalStateException("already declared: " + method);
- }
- MethodDeclaration methodDeclaration = new MethodDeclaration(method, flags);
- typeDeclaration.methods.put(method, methodDeclaration);
- return methodDeclaration.code;
- }
-
- /**
- * @param flags any flags masked by {@link AccessFlags#FIELD_FLAGS}.
- */
- public void declare(FieldId<?, ?> fieldId, int flags, Object staticValue) {
- TypeDeclaration typeDeclaration = getTypeDeclaration(fieldId.declaringType);
- if (typeDeclaration.fields.containsKey(fieldId)) {
- throw new IllegalStateException("already declared: " + fieldId);
- }
- FieldDeclaration fieldDeclaration = new FieldDeclaration(fieldId, flags, staticValue);
- typeDeclaration.fields.put(fieldId, fieldDeclaration);
- }
-
- /**
- * Returns a .dex formatted file.
- */
- public byte[] generate() {
- DexOptions options = new DexOptions();
- options.targetApiLevel = DexFormat.API_NO_EXTENDED_OPCODES;
- DexFile outputDex = new DexFile(options);
-
- for (TypeDeclaration typeDeclaration : types.values()) {
- outputDex.add(typeDeclaration.toClassDefItem());
- }
-
- try {
- return outputDex.toDex(null, false);
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Loads the generated types into the current process.
- *
- * <p>All parameters are optional, you may pass {@code null} and suitable
- * defaults will be used.
- *
- * <p>If you opt to provide your own output directories, take care to
- * ensure that they are not world-readable, otherwise a malicious app will
- * be able to inject code to run. A suitable parameter for these output
- * directories would be something like this:
- * {@code getApplicationContext().getDir("dx", Context.MODE_PRIVATE); }
- *
- * @param parent the parent ClassLoader to be used when loading
- * our generated types
- * @param dexOutputDir the destination directory wherein we will write
- * 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)
- throws IOException {
- byte[] dex = generate();
-
- /*
- * This implementation currently dumps the dex to the filesystem. It
- * jars the emitted .dex for the benefit of Gingerbread and earlier
- * devices, which can't load .dex files directly.
- *
- * TODO: load the dex from memory where supported.
- */
- File result = File.createTempFile("Generated", ".jar", dexOutputDir);
- result.deleteOnExit();
- JarOutputStream jarOut = new JarOutputStream(new FileOutputStream(result));
- jarOut.putNextEntry(new JarEntry(DexFormat.DEX_IN_JAR_NAME));
- jarOut.write(dex);
- jarOut.closeEntry();
- jarOut.close();
- try {
- return (ClassLoader) Class.forName("dalvik.system.DexClassLoader")
- .getConstructor(String.class, String.class, String.class, ClassLoader.class)
- .newInstance(result.getPath(), dexOptCacheDir.getAbsolutePath(), null, parent);
- } catch (ClassNotFoundException e) {
- throw new UnsupportedOperationException("load() requires a Dalvik VM", e);
- } catch (InvocationTargetException e) {
- throw new RuntimeException(e.getCause());
- } catch (InstantiationException e) {
- throw new AssertionError();
- } catch (NoSuchMethodException e) {
- throw new AssertionError();
- } catch (IllegalAccessException e) {
- throw new AssertionError();
- }
- }
-
- private static class TypeDeclaration {
- private final Type<?> type;
-
- /** declared state */
- private boolean declared;
- private int flags;
- private Type<?> supertype;
- private String sourceFile;
- private TypeList interfaces;
-
- private final Map<FieldId, FieldDeclaration> fields
- = new LinkedHashMap<FieldId, FieldDeclaration>();
- private final Map<MethodId, MethodDeclaration> methods
- = new LinkedHashMap<MethodId, MethodDeclaration>();
-
- TypeDeclaration(Type<?> type) {
- this.type = type;
- }
-
- ClassDefItem toClassDefItem() {
- if (!declared) {
- throw new IllegalStateException("Undeclared type " + type + " declares members: "
- + fields.keySet() + " " + methods.keySet());
- }
-
- DexOptions dexOptions = new DexOptions();
- dexOptions.targetApiLevel = DexFormat.API_NO_EXTENDED_OPCODES;
-
- CstType thisType = type.constant;
-
- ClassDefItem out = new ClassDefItem(thisType, flags, supertype.constant,
- interfaces.ropTypes, new CstString(sourceFile));
-
- for (MethodDeclaration method : methods.values()) {
- EncodedMethod encoded = method.toEncodedMethod(dexOptions);
- if (method.isDirect()) {
- out.addDirectMethod(encoded);
- } else {
- out.addVirtualMethod(encoded);
- }
- }
- for (FieldDeclaration field : fields.values()) {
- EncodedField encoded = field.toEncodedField();
- if (field.isStatic()) {
- out.addStaticField(encoded, Constants.getConstant(field.staticValue));
- } else {
- out.addInstanceField(encoded);
- }
- }
-
- return out;
- }
- }
-
- static class FieldDeclaration {
- final FieldId<?, ?> fieldId;
- private final int accessFlags;
- private final Object staticValue;
-
- FieldDeclaration(FieldId<?, ?> fieldId, int accessFlags, Object staticValue) {
- if ((accessFlags & (AccessFlags.ACC_STATIC)) == 0 && staticValue != null) {
- throw new IllegalArgumentException("instance fields may not have a value");
- }
- this.fieldId = fieldId;
- this.accessFlags = accessFlags;
- this.staticValue = staticValue;
- }
-
- EncodedField toEncodedField() {
- return new EncodedField(fieldId.constant, accessFlags);
- }
-
- public boolean isStatic() {
- return (accessFlags & (AccessFlags.ACC_STATIC)) != 0;
- }
- }
-
- static class MethodDeclaration {
- final MethodId<?, ?> method;
- private final int flags;
- private final Code code;
-
- public MethodDeclaration(MethodId<?, ?> method, int flags) {
- this.method = method;
- this.flags = flags;
- this.code = new Code(this);
- }
-
- boolean isStatic() {
- return (flags & ACC_STATIC) != 0;
- }
-
- boolean isDirect() {
- return (flags & (ACC_STATIC | ACC_PRIVATE | ACC_CONSTRUCTOR)) != 0;
- }
-
- EncodedMethod toEncodedMethod(DexOptions dexOptions) {
- RopMethod ropMethod = new RopMethod(code.toBasicBlocks(), 0);
- LocalVariableInfo locals = null;
- DalvCode dalvCode = RopTranslator.translate(
- ropMethod, PositionList.NONE, locals, code.paramSize(), dexOptions);
- return new EncodedMethod(method.constant, flags, dalvCode, StdTypeList.EMPTY);
- }
- }
-}
diff --git a/dx/src/com/android/dx/gen/FieldId.java b/dx/src/com/android/dx/gen/FieldId.java
deleted file mode 100644
index 62ef73bdd..000000000
--- a/dx/src/com/android/dx/gen/FieldId.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2011 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.android.dx.gen;
-
-import com.android.dx.rop.cst.CstFieldRef;
-import com.android.dx.rop.cst.CstNat;
-import com.android.dx.rop.cst.CstString;
-
-/**
- * A field.
- */
-public final class FieldId<D, V> {
- final Type<D> declaringType;
- final Type<V> type;
- final String name;
-
- /** cached converted state */
- final CstNat nat;
- final CstFieldRef constant;
-
- FieldId(Type<D> declaringType, Type<V> type, String name) {
- if (declaringType == null || type == null || name == null) {
- throw new NullPointerException();
- }
- this.declaringType = declaringType;
- this.type = type;
- this.name = name;
- this.nat = new CstNat(new CstString(name), new CstString(type.name));
- this.constant = new CstFieldRef(declaringType.constant, nat);
- }
-
- public Type<D> getDeclaringType() {
- return declaringType;
- }
-
- public Type<V> getType() {
- return type;
- }
-
- public String getName() {
- return name;
- }
-
- @Override public boolean equals(Object o) {
- return o instanceof FieldId
- && ((FieldId<?, ?>) o).declaringType.equals(declaringType)
- && ((FieldId<?, ?>) o).name.equals(name);
- }
-
- @Override public int hashCode() {
- return declaringType.hashCode() + 37 * name.hashCode();
- }
-
- @Override public String toString() {
- return declaringType + "." + name;
- }
-}
diff --git a/dx/src/com/android/dx/gen/Label.java b/dx/src/com/android/dx/gen/Label.java
deleted file mode 100644
index 633b5f161..000000000
--- a/dx/src/com/android/dx/gen/Label.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2011 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.android.dx.gen;
-
-import com.android.dx.rop.code.BasicBlock;
-import com.android.dx.rop.code.Insn;
-import com.android.dx.rop.code.InsnList;
-import com.android.dx.util.IntList;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * A branch target in a list of instructions.
- */
-public final class Label {
-
- final List<Insn> instructions = new ArrayList<Insn>();
-
- boolean marked = false;
-
- /** an immutable list of labels corresponding to the types in the catch list */
- List<Label> catchLabels = Collections.emptyList();
-
- /** contains the next instruction if no branch occurs */
- Label primarySuccessor;
-
- /** contains the instruction to jump to if the if is true */
- Label alternateSuccessor;
-
- int id = -1;
-
- Label() {}
-
- boolean isEmpty() {
- return instructions.isEmpty();
- }
-
- void compact() {
- for (int i = 0; i < catchLabels.size(); i++) {
- while (catchLabels.get(i).isEmpty()) {
- catchLabels.set(i, catchLabels.get(i).primarySuccessor);
- }
- }
- while (primarySuccessor != null && primarySuccessor.isEmpty()) {
- primarySuccessor = primarySuccessor.primarySuccessor;
- }
- while (alternateSuccessor != null && alternateSuccessor.isEmpty()) {
- alternateSuccessor = alternateSuccessor.primarySuccessor;
- }
- }
-
- BasicBlock toBasicBlock() {
- InsnList result = new InsnList(instructions.size());
- for (int i = 0; i < instructions.size(); i++) {
- result.set(i, instructions.get(i));
- }
- result.setImmutable();
-
- int primarySuccessorIndex = -1;
- IntList successors = new IntList();
- for (Label catchLabel : catchLabels) {
- successors.add(catchLabel.id);
- }
- if (primarySuccessor != null) {
- primarySuccessorIndex = primarySuccessor.id;
- successors.add(primarySuccessorIndex);
- }
- if (alternateSuccessor != null) {
- successors.add(alternateSuccessor.id);
- }
- successors.setImmutable();
-
- return new BasicBlock(id, result, successors, primarySuccessorIndex);
- }
-}
diff --git a/dx/src/com/android/dx/gen/Local.java b/dx/src/com/android/dx/gen/Local.java
deleted file mode 100644
index b98759c3f..000000000
--- a/dx/src/com/android/dx/gen/Local.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2011 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.android.dx.gen;
-
-import com.android.dx.rop.code.RegisterSpec;
-
-/**
- * A temporary variable that holds a single value.
- */
-public final class Local<T> {
- private final Code code;
- final Type<T> type;
- private int reg = -1;
- private RegisterSpec spec;
-
- private Local(Code code, Type<T> type) {
- this.code = code;
- this.type = type;
- }
-
- static <T> Local<T> get(Code code, Type<T> type) {
- return new Local<T>(code, type);
- }
-
- /**
- * Assigns registers to this local.
- *
- * @return the number of registers required.
- */
- int initialize(int reg) {
- this.reg = reg;
- this.spec = RegisterSpec.make(reg, type.ropType);
- return size();
- }
-
- int size() {
- return type.ropType.getCategory();
- }
-
- RegisterSpec spec() {
- if (spec == null) {
- code.initializeLocals();
- if (spec == null) {
- throw new AssertionError();
- }
- }
- return spec;
- }
-
- public Type getType() {
- return type;
- }
-
- @Override public String toString() {
- return "v" + reg + "(" + type + ")";
- }
-}
diff --git a/dx/src/com/android/dx/gen/MethodId.java b/dx/src/com/android/dx/gen/MethodId.java
deleted file mode 100644
index 29d088ab4..000000000
--- a/dx/src/com/android/dx/gen/MethodId.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (C) 2011 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.android.dx.gen;
-
-import com.android.dx.rop.cst.CstMethodRef;
-import com.android.dx.rop.cst.CstNat;
-import com.android.dx.rop.cst.CstString;
-import com.android.dx.rop.type.Prototype;
-import java.util.List;
-
-/**
- * A method or constructor.
- */
-public final class MethodId<D, R> {
- final Type<D> declaringType;
- final Type<R> returnType;
- final String name;
- final TypeList parameters;
-
- /** cached converted state */
- final CstNat nat;
- final CstMethodRef constant;
-
- MethodId(Type<D> declaringType, Type<R> returnType, String name, TypeList parameters) {
- if (declaringType == null || returnType == null || name == null || parameters == null) {
- throw new NullPointerException();
- }
- this.declaringType = declaringType;
- this.returnType = returnType;
- this.name = name;
- this.parameters = parameters;
- this.nat = new CstNat(new CstString(name), new CstString(descriptor(false)));
- this.constant = new CstMethodRef(declaringType.constant, nat);
- }
-
- public Type<D> getDeclaringType() {
- return declaringType;
- }
-
- public Type<R> getReturnType() {
- return returnType;
- }
-
- public String getName() {
- return name;
- }
-
- public List<Type<?>> getParameters() {
- return parameters.asList();
- }
-
- /**
- * Returns a descriptor like "(Ljava/lang/Class;[I)Ljava/lang/Object;".
- */
- String descriptor(boolean includeThis) {
- StringBuilder result = new StringBuilder();
- result.append("(");
- if (includeThis) {
- result.append(declaringType.name);
- }
- for (Type t : parameters.types) {
- result.append(t.name);
- }
- result.append(")");
- result.append(returnType.name);
- return result.toString();
- }
-
- Prototype prototype(boolean includeThis) {
- return Prototype.intern(descriptor(includeThis));
- }
-
- @Override public boolean equals(Object o) {
- return o instanceof MethodId
- && ((MethodId<?, ?>) o).declaringType.equals(declaringType)
- && ((MethodId<?, ?>) o).name.equals(name)
- && ((MethodId<?, ?>) o).parameters.equals(parameters)
- && ((MethodId<?, ?>) o).returnType.equals(returnType);
- }
-
- @Override public int hashCode() {
- int result = 17;
- result = 31 * result + declaringType.hashCode();
- result = 31 * result + name.hashCode();
- result = 31 * result + parameters.hashCode();
- result = 31 * result + returnType.hashCode();
- return result;
- }
-
- @Override public String toString() {
- return declaringType + "." + name + "(" + parameters + ")";
- }
-}
diff --git a/dx/src/com/android/dx/gen/ProxyBuilder.java b/dx/src/com/android/dx/gen/ProxyBuilder.java
deleted file mode 100644
index 852fe666f..000000000
--- a/dx/src/com/android/dx/gen/ProxyBuilder.java
+++ /dev/null
@@ -1,667 +0,0 @@
-/*
- * Copyright (C) 2011 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.android.dx.gen;
-
-import static com.android.dx.rop.code.AccessFlags.ACC_CONSTRUCTOR;
-import static com.android.dx.rop.code.AccessFlags.ACC_PRIVATE;
-import static com.android.dx.rop.code.AccessFlags.ACC_PUBLIC;
-import static com.android.dx.rop.code.AccessFlags.ACC_STATIC;
-
-import java.io.File;
-import java.io.IOException;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.lang.reflect.UndeclaredThrowableException;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Creates dynamic proxies of concrete classes.
- * <p>
- * This is similar to the {@code java.lang.reflect.Proxy} class, but works for classes instead of
- * interfaces.
- * <h3>Example</h3>
- * The following example demonstrates the creation of a dynamic proxy for {@code java.util.Random}
- * which will always return 4 when asked for integers, and which logs method calls to every method.
- * <pre>
- * InvocationHandler handler = new InvocationHandler() {
- * &#64;Override
- * public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- * if (method.getName().equals("nextInt")) {
- * // Chosen by fair dice roll, guaranteed to be random.
- * return 4;
- * }
- * Object result = ProxyBuilder.callSuper(proxy, method, args);
- * System.out.println("Method: " + method.getName() + " args: "
- * + Arrays.toString(args) + " result: " + result);
- * return result;
- * }
- * };
- * Random debugRandom = ProxyBuilder.forClass(Random.class)
- * .dexCache(getInstrumentation().getTargetContext().getDir("dx", Context.MODE_PRIVATE))
- * .handler(handler)
- * .build();
- * assertEquals(4, debugRandom.nextInt());
- * debugRandom.setSeed(0);
- * assertTrue(debugRandom.nextBoolean());
- * </pre>
- * <h3>Usage</h3>
- * Call {@link #forClass(Class)} for the Class you wish to proxy. Call
- * {@link #handler(InvocationHandler)} passing in an {@link InvocationHandler}, and then call
- * {@link #build()}. The returned instance will be a dynamically generated subclass where all method
- * calls will be delegated to the invocation handler, except as noted below.
- * <p>
- * The static method {@link #callSuper(Object, Method, Object...)} allows you to access the original
- * super method for a given proxy. This allows the invocation handler to selectively override some
- * methods but not others.
- * <p>
- * By default, the {@link #build()} method will call the no-arg constructor belonging to the class
- * being proxied. If you wish to call a different constructor, you must provide arguments for both
- * {@link #constructorArgTypes(Class[])} and {@link #constructorArgValues(Object[])}.
- * <p>
- * This process works only for classes with public and protected level of visibility.
- * <p>
- * You may proxy abstract classes. You may not proxy final classes.
- * <p>
- * Only non-private, non-final, non-static methods will be dispatched to the invocation handler.
- * Private, static or final methods will always call through to the superclass as normal.
- * <p>
- * The {@link #finalize()} method on {@code Object} will not be proxied.
- * <p>
- * You must provide a dex cache directory via the {@link #dexCache(File)} method. You should take
- * care not to make this a world-writable directory, so that third parties cannot inject code into
- * your application. A suitable parameter for these output directories would be something like
- * this:
- * <pre>{@code
- * getApplicationContext().getDir("dx", Context.MODE_PRIVATE);
- * }</pre>
- * <p>
- * If the base class to be proxied leaks the {@code this} pointer in the constructor (bad practice),
- * that is to say calls a non-private non-final method from the constructor, the invocation handler
- * will not be invoked. As a simple concrete example, when proxying Random we discover that it
- * inernally calls setSeed during the constructor. The proxy will not intercept this call during
- * proxy construction, but will intercept as normal afterwards. This behaviour may be subject to
- * change in future releases.
- * <p>
- * This class is <b>not thread safe</b>.
- */
-public final class ProxyBuilder<T> {
- private static final String FIELD_NAME_HANDLER = "$__handler";
- private static final String FIELD_NAME_METHODS = "$__methodArray";
-
- private final Class<T> baseClass;
- private ClassLoader parentClassLoader = ProxyBuilder.class.getClassLoader();
- private InvocationHandler handler;
- private File dexCache;
- private Class<?>[] constructorArgTypes = new Class[0];
- private Object[] constructorArgValues = new Object[0];
-
- private ProxyBuilder(Class<T> clazz) {
- baseClass = clazz;
- }
-
- public static <T> ProxyBuilder<T> forClass(Class<T> clazz) {
- return new ProxyBuilder<T>(clazz);
- }
-
- /**
- * Specifies the parent ClassLoader to use when creating the proxy.
- *
- * <p>If null, {@code ProxyBuilder.class.getClassLoader()} will be used.
- */
- public ProxyBuilder<T> parentClassLoader(ClassLoader parent) {
- parentClassLoader = parent;
- return this;
- }
-
- public ProxyBuilder<T> handler(InvocationHandler handler) {
- this.handler = handler;
- return this;
- }
-
- public ProxyBuilder<T> dexCache(File dexCache) {
- this.dexCache = dexCache;
- return this;
- }
-
- public ProxyBuilder<T> constructorArgValues(Object... constructorArgValues) {
- this.constructorArgValues = constructorArgValues;
- return this;
- }
-
- public ProxyBuilder<T> constructorArgTypes(Class<?>... constructorArgTypes) {
- this.constructorArgTypes = constructorArgTypes;
- return this;
- }
-
- /**
- * Create a new instance of the class to proxy.
- *
- * @throws UnsupportedOperationException if the class we are trying to create a proxy for is
- * not accessible.
- * @throws DexCacheException if an exception occurred writing to the {@code dexCache} directory.
- * @throws UndeclaredThrowableException if the constructor for the base class to proxy throws
- * a declared exception during construction.
- * @throws IllegalArgumentException if the handler is null, if the constructor argument types
- * do not match the constructor argument values, or if no such constructor exists.
- */
- public T build() {
- check(handler != null, "handler == null");
- check(constructorArgTypes.length == constructorArgValues.length,
- "constructorArgValues.length != constructorArgTypes.length");
- DexGenerator generator = new DexGenerator();
- String generatedName = getMethodNameForProxyOf(baseClass);
- Type<? extends T> generatedType = Type.get("L" + generatedName + ";");
- Type<T> superType = Type.get(baseClass);
- generateConstructorsAndFields(generator, generatedType, superType, baseClass);
- Method[] methodsToProxy = getMethodsToProxy(baseClass);
- generateCodeForAllMethods(generator, generatedType, methodsToProxy, superType);
- generator.declare(generatedType, generatedName + ".generated", ACC_PUBLIC, superType);
- ClassLoader classLoader;
- try {
- classLoader = generator.load(parentClassLoader, dexCache, dexCache);
- } catch (IOException e) {
- throw new DexCacheException(e);
- }
- Class<? extends T> proxyClass;
- try {
- proxyClass = loadClass(classLoader, generatedName);
- } catch (IllegalAccessError e) {
- // Thrown when the base class is not accessible.
- throw new UnsupportedOperationException("cannot proxy inaccessible classes", e);
- } catch (ClassNotFoundException e) {
- // Should not be thrown, we're sure to have generated this class.
- throw new AssertionError(e);
- }
- setMethodsStaticField(proxyClass, methodsToProxy);
- Constructor<? extends T> constructor;
- try {
- constructor = proxyClass.getConstructor(constructorArgTypes);
- } catch (NoSuchMethodException e) {
- // Thrown when the ctor to be called does not exist.
- throw new IllegalArgumentException("could not find matching constructor", e);
- }
- T result;
- try {
- result = constructor.newInstance(constructorArgValues);
- } catch (InstantiationException e) {
- // Should not be thrown, generated class is not abstract.
- throw new AssertionError(e);
- } catch (IllegalAccessException e) {
- // Should not be thrown, the generated constructor is accessible.
- throw new AssertionError(e);
- } catch (InvocationTargetException e) {
- // Thrown when the base class ctor throws an exception.
- throw launderCause(e);
- }
- setHandlerInstanceField(result, handler);
- return result;
- }
-
- // The type cast is safe: the generated type will extend the base class type.
- @SuppressWarnings("unchecked")
- private Class<? extends T> loadClass(ClassLoader classLoader, String generatedName)
- throws ClassNotFoundException {
- return (Class<? extends T>) classLoader.loadClass(generatedName);
- }
-
- private static RuntimeException launderCause(InvocationTargetException e) {
- Throwable cause = e.getCause();
- // Errors should be thrown as they are.
- if (cause instanceof Error) {
- throw (Error) cause;
- }
- // RuntimeException can be thrown as-is.
- if (cause instanceof RuntimeException) {
- throw (RuntimeException) cause;
- }
- // Declared exceptions will have to be wrapped.
- throw new UndeclaredThrowableException(cause);
- }
-
- private static void setHandlerInstanceField(Object instance, InvocationHandler handler) {
- try {
- Field handlerField = instance.getClass().getDeclaredField(FIELD_NAME_HANDLER);
- handlerField.setAccessible(true);
- handlerField.set(instance, handler);
- } catch (NoSuchFieldException e) {
- // Should not be thrown, generated proxy class has been generated with this field.
- throw new AssertionError(e);
- } catch (IllegalAccessException e) {
- // Should not be thrown, we just set the field to accessible.
- throw new AssertionError(e);
- }
- }
-
- private static void setMethodsStaticField(Class<?> proxyClass, Method[] methodsToProxy) {
- try {
- Field methodArrayField = proxyClass.getDeclaredField(FIELD_NAME_METHODS);
- methodArrayField.setAccessible(true);
- methodArrayField.set(null, methodsToProxy);
- } catch (NoSuchFieldException e) {
- // Should not be thrown, generated proxy class has been generated with this field.
- throw new AssertionError(e);
- } catch (IllegalAccessException e) {
- // Should not be thrown, we just set the field to accessible.
- throw new AssertionError(e);
- }
- }
-
- /**
- * Returns the proxy's {@link InvocationHandler}.
- *
- * @throws IllegalArgumentException if the object supplied is not a proxy created by this class.
- */
- public static InvocationHandler getInvocationHandler(Object instance) {
- try {
- Field field = instance.getClass().getDeclaredField(FIELD_NAME_HANDLER);
- field.setAccessible(true);
- return (InvocationHandler) field.get(instance);
- } catch (NoSuchFieldException e) {
- throw new IllegalArgumentException("Not a valid proxy instance", e);
- } catch (IllegalAccessException e) {
- // Should not be thrown, we just set the field to accessible.
- throw new AssertionError(e);
- }
- }
-
- private static <T, G extends T> void generateCodeForAllMethods(DexGenerator generator,
- Type<G> generatedType, Method[] methodsToProxy, Type<T> superclassType) {
- Type<InvocationHandler> handlerType = Type.get(InvocationHandler.class);
- Type<Method[]> methodArrayType = Type.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);
- for (int m = 0; m < methodsToProxy.length; ++m) {
- /*
- * If the 5th method on the superclass Example that can be overridden were to look like
- * this:
- *
- * public int doSomething(Bar param0, int param1) {
- * ...
- * }
- *
- * Then the following code will generate a method on the proxy that looks something
- * like this:
- *
- * public int doSomething(Bar param0, int param1) {
- * int methodIndex = 4;
- * Method[] allMethods = Example_Proxy.$__methodArray;
- * Method thisMethod = allMethods[methodIndex];
- * int argsLength = 2;
- * Object[] args = new Object[argsLength];
- * InvocationHandler localHandler = this.$__handler;
- * // for-loop begins
- * int p = 0;
- * Bar parameter0 = param0;
- * args[p] = parameter0;
- * p = 1;
- * int parameter1 = param1;
- * Integer boxed1 = Integer.valueOf(parameter1);
- * args[p] = boxed1;
- * // for-loop ends
- * Object result = localHandler.invoke(this, thisMethod, args);
- * Integer castResult = (Integer) result;
- * int unboxedResult = castResult.intValue();
- * return unboxedResult;
- * }
- *
- * Or, in more idiomatic Java:
- *
- * public int doSomething(Bar param0, int param1) {
- * if ($__handler == null) {
- * return super.doSomething(param0, param1);
- * }
- * return __handler.invoke(this, __methodArray[4],
- * new Object[] { param0, Integer.valueOf(param1) });
- * }
- */
- Method method = methodsToProxy[m];
- String name = method.getName();
- Class<?>[] argClasses = method.getParameterTypes();
- Type<?>[] argTypes = new Type<?>[argClasses.length];
- for (int i = 0; i < argTypes.length; ++i) {
- argTypes[i] = Type.get(argClasses[i]);
- }
- Class<?> returnType = method.getReturnType();
- Type<?> resultType = Type.get(returnType);
- MethodId<T, ?> superMethod = superclassType.getMethod(resultType, name, argTypes);
- MethodId<?, ?> methodId = generatedType.getMethod(resultType, name, argTypes);
- Code code = generator.declare(methodId, ACC_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[]> args = code.newLocal(objectArrayType);
- Local<Integer> argsLength = code.newLocal(Type.INT);
- Local<Object> temp = code.newLocal(Type.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);
- Class<?> aBoxedClass = PRIMITIVE_TO_BOXED.get(returnType);
- Local<?> aBoxedResult = null;
- if (aBoxedClass != null) {
- aBoxedResult = code.newLocal(Type.get(aBoxedClass));
- }
- Local<?>[] superArgs2 = new Local<?>[argClasses.length];
- Local<?> superResult2 = code.newLocal(resultType);
- Local<InvocationHandler> nullHandler = code.newLocal(handlerType);
-
- code.loadConstant(methodIndex, m);
- code.sget(allMethods, methodArray);
- code.aget(methodArray, methodIndex, thisMethod);
- code.loadConstant(argsLength, argTypes.length);
- code.newArray(argsLength, args);
- code.iget(handlerField, localThis, localHandler);
-
- // if (proxy == null)
- code.loadConstant(nullHandler, null);
- Label handlerNullCase = code.newLabel();
- code.compare(Comparison.EQ, nullHandler, localHandler, handlerNullCase);
-
- // This code is what we execute when we have a valid proxy: delegate to invocation
- // handler.
- for (int p = 0; p < argTypes.length; ++p) {
- code.loadConstant(intValue, p);
- Local<?> parameter = code.getParameter(p, argTypes[p]);
- Local<?> unboxedIfNecessary = boxIfRequired(generator, code, parameter, temp);
- code.aput(args, intValue, unboxedIfNecessary);
- }
- code.invokeInterface(methodInvoke, invokeResult, localHandler,
- localThis, thisMethod, args);
- generateCodeForReturnStatement(code, returnType, invokeResult, resultHolder,
- aBoxedResult);
-
- // This code is executed if proxy is null: call the original super method.
- // This is required to handle the case of construction of an object which leaks the
- // "this" pointer.
- code.mark(handlerNullCase);
- for (int i = 0; i < superArgs2.length; ++i) {
- superArgs2[i] = code.getParameter(i, argTypes[i]);
- }
- if (void.class.equals(returnType)) {
- code.invokeSuper(superMethod, null, localThis, superArgs2);
- code.returnVoid();
- } else {
- invokeSuper(superMethod, code, localThis, superArgs2, superResult2);
- code.returnValue(superResult2);
- }
-
- /*
- * And to allow calling the original super method, the following is also generated:
- *
- * public int super_doSomething(Bar param0, int param1) {
- * int result = super.doSomething(param0, param1);
- * return result;
- * }
- */
- String superName = "super_" + name;
- MethodId<G, ?> callsSuperMethod = generatedType.getMethod(
- resultType, superName, argTypes);
- Code superCode = generator.declare(callsSuperMethod, ACC_PUBLIC);
- Local<G> superThis = superCode.getThis(generatedType);
- Local<?>[] superArgs = new Local<?>[argClasses.length];
- for (int i = 0; i < superArgs.length; ++i) {
- superArgs[i] = superCode.getParameter(i, argTypes[i]);
- }
- if (void.class.equals(returnType)) {
- superCode.invokeSuper(superMethod, null, superThis, superArgs);
- superCode.returnVoid();
- } else {
- Local<?> superResult = superCode.newLocal(resultType);
- invokeSuper(superMethod, superCode, superThis, superArgs, superResult);
- superCode.returnValue(superResult);
- }
- }
- }
-
- // This one is tricky to fix, I gave up.
- @SuppressWarnings({ "unchecked", "rawtypes" })
- private static <T> void invokeSuper(MethodId superMethod, Code superCode,
- Local superThis, Local[] superArgs, Local superResult) {
- superCode.invokeSuper(superMethod, superResult, superThis, superArgs);
- }
-
- private static Local<?> boxIfRequired(DexGenerator generator, Code code, Local<?> parameter,
- Local<Object> temp) {
- MethodId<?, ?> unboxMethod = PRIMITIVE_TYPE_TO_UNBOX_METHOD.get(parameter.getType());
- if (unboxMethod == null) {
- return parameter;
- }
- code.invokeStatic(unboxMethod, temp, parameter);
- return temp;
- }
-
- public static Object callSuper(Object proxy, Method method, Object... args)
- throws SecurityException, IllegalAccessException,
- InvocationTargetException, NoSuchMethodException {
- return proxy.getClass()
- .getMethod("super_" + method.getName(), method.getParameterTypes())
- .invoke(proxy, args);
- }
-
- private static void check(boolean condition, String message) {
- if (!condition) {
- throw new IllegalArgumentException(message);
- }
- }
-
- private static <T, G extends T> void generateConstructorsAndFields(DexGenerator generator,
- Type<G> generatedType, Type<T> superType, Class<T> superClass) {
- Type<InvocationHandler> handlerType = Type.get(InvocationHandler.class);
- Type<Method[]> methodArrayType = Type.get(Method[].class);
- FieldId<G, InvocationHandler> handlerField = generatedType.getField(
- handlerType, FIELD_NAME_HANDLER);
- generator.declare(handlerField, ACC_PRIVATE, null);
- FieldId<G, Method[]> allMethods = generatedType.getField(
- methodArrayType, FIELD_NAME_METHODS);
- generator.declare(allMethods, ACC_PRIVATE | ACC_STATIC, null);
- for (Constructor<T> constructor : getConstructorsToOverwrite(superClass)) {
- if (constructor.getModifiers() == Modifier.FINAL) {
- continue;
- }
- Type<?>[] types = classArrayToTypeArray(constructor.getParameterTypes());
- MethodId<?, ?> method = generatedType.getConstructor(types);
- Code constructorCode = generator.declare(method, ACC_PUBLIC | ACC_CONSTRUCTOR);
- Local<G> thisRef = constructorCode.getThis(generatedType);
- Local<?>[] params = new Local[types.length];
- for (int i = 0; i < params.length; ++i) {
- params[i] = constructorCode.getParameter(i, types[i]);
- }
- MethodId<T, ?> superConstructor = superType.getConstructor(types);
- constructorCode.invokeDirect(superConstructor, null, thisRef, params);
- constructorCode.returnVoid();
- }
- }
-
- // The type parameter on Constructor is the class in which the constructor is declared.
- // The getDeclaredConstructors() method gets constructors declared only in the given class,
- // hence this cast is safe.
- @SuppressWarnings("unchecked")
- private static <T> Constructor<T>[] getConstructorsToOverwrite(Class<T> clazz) {
- return (Constructor<T>[]) clazz.getDeclaredConstructors();
- }
-
- /**
- * Gets all {@link Method} objects we can proxy in the hierarchy of the supplied class.
- */
- private static <T> Method[] getMethodsToProxy(Class<T> clazz) {
- Set<MethodSetEntry> methodsToProxy = new HashSet<MethodSetEntry>();
- for (Class<?> current = clazz; current != null; current = current.getSuperclass()) {
- for (Method method : current.getDeclaredMethods()) {
- if ((method.getModifiers() & Modifier.FINAL) != 0) {
- // Skip final methods, we can't override them.
- continue;
- }
- if ((method.getModifiers() & Modifier.STATIC) != 0) {
- // Skip static methods, overriding them has no effect.
- continue;
- }
- if (method.getName().equals("finalize") && method.getParameterTypes().length == 0) {
- // Skip finalize method, it's likely important that it execute as normal.
- continue;
- }
- methodsToProxy.add(new MethodSetEntry(method));
- }
- }
- Method[] results = new Method[methodsToProxy.size()];
- int i = 0;
- for (MethodSetEntry entry : methodsToProxy) {
- results[i++] = entry.originalMethod;
- }
- return results;
- }
-
- private static <T> String getMethodNameForProxyOf(Class<T> clazz) {
- return clazz.getSimpleName() + "_Proxy";
- }
-
- private static Type<?>[] classArrayToTypeArray(Class<?>[] input) {
- Type<?>[] result = new Type[input.length];
- for (int i = 0; i < input.length; ++i) {
- result[i] = Type.get(input[i]);
- }
- return result;
- }
-
- /**
- * Calculates the correct return statement code for a method.
- * <p>
- * A void method will not return anything. A method that returns a primitive will need to
- * unbox the boxed result. Otherwise we will cast the result.
- */
- // This one is tricky to fix, I gave up.
- @SuppressWarnings({ "rawtypes", "unchecked" })
- 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);
- 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.returnValue(localOfMethodReturnType);
- }
- }
-
- private static MethodId<?, ?> getUnboxMethodForPrimitive(Class<?> methodReturnType) {
- return PRIMITIVE_TO_UNBOX_METHOD.get(methodReturnType);
- }
-
- private static final Map<Class<?>, Class<?>> PRIMITIVE_TO_BOXED;
- static {
- PRIMITIVE_TO_BOXED = new HashMap<Class<?>, Class<?>>();
- PRIMITIVE_TO_BOXED.put(boolean.class, Boolean.class);
- PRIMITIVE_TO_BOXED.put(int.class, Integer.class);
- PRIMITIVE_TO_BOXED.put(byte.class, Byte.class);
- PRIMITIVE_TO_BOXED.put(long.class, Long.class);
- PRIMITIVE_TO_BOXED.put(short.class, Short.class);
- PRIMITIVE_TO_BOXED.put(float.class, Float.class);
- PRIMITIVE_TO_BOXED.put(double.class, Double.class);
- PRIMITIVE_TO_BOXED.put(char.class, Character.class);
- }
-
- private static final Map<Type<?>, MethodId<?, ?>> PRIMITIVE_TYPE_TO_UNBOX_METHOD;
- static {
- PRIMITIVE_TYPE_TO_UNBOX_METHOD = new HashMap<Type<?>, MethodId<?, ?>>();
- for (Map.Entry<Class<?>, Class<?>> entry : PRIMITIVE_TO_BOXED.entrySet()) {
- Type<?> primitiveType = Type.get(entry.getKey());
- Type<?> boxedType = Type.get(entry.getValue());
- MethodId<?, ?> valueOfMethod = boxedType.getMethod(boxedType, "valueOf", primitiveType);
- PRIMITIVE_TYPE_TO_UNBOX_METHOD.put(primitiveType, valueOfMethod);
- }
- }
-
- /**
- * Map from primitive type to method used to unbox a boxed version of the primitive.
- * <p>
- * This is required for methods whose return type is primitive, since the
- * {@link InvocationHandler} will return us a boxed result, and we'll need to convert it back to
- * primitive value.
- */
- 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"));
- PRIMITIVE_TO_UNBOX_METHOD = map;
- }
-
- /**
- * Wrapper class to let us disambiguate {@link Method} objects.
- * <p>
- * The purpose of this class is to override the {@link #equals(Object)} and {@link #hashCode()}
- * methods so we can use a {@link Set} to remove duplicate methods that are overrides of one
- * another. For these purposes, we consider two methods to be equal if they have the same
- * name, return type, and parameter types.
- */
- private static class MethodSetEntry {
- private final String name;
- private final Class<?>[] paramTypes;
- private final Class<?> returnType;
- private final Method originalMethod;
-
- public MethodSetEntry(Method method) {
- originalMethod = method;
- name = method.getName();
- paramTypes = method.getParameterTypes();
- returnType = method.getReturnType();
- }
-
- @Override
- public boolean equals(Object o) {
- if (o instanceof MethodSetEntry) {
- MethodSetEntry other = (MethodSetEntry) o;
- return name.equals(other.name)
- && returnType.equals(other.returnType)
- && Arrays.equals(paramTypes, other.paramTypes);
- }
- return false;
- }
-
- @Override
- public int hashCode() {
- int result = 17;
- result += 31 * result + name.hashCode();
- result += 31 * result + returnType.hashCode();
- result += 31 * result + Arrays.hashCode(paramTypes);
- return result;
- }
- }
-}
diff --git a/dx/src/com/android/dx/gen/Type.java b/dx/src/com/android/dx/gen/Type.java
deleted file mode 100644
index 3b81f6d1d..000000000
--- a/dx/src/com/android/dx/gen/Type.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) 2011 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.android.dx.gen;
-
-import com.android.dx.rop.cst.CstType;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * A primitive type, interface or class.
- */
-public final class Type<T> {
- /** The {@code boolean} primitive type. */
- public static final Type<Boolean> BOOLEAN
- = new Type<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);
-
- /** The {@code char} primitive type. */
- public static final Type<Character> CHAR
- = new Type<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);
-
- /** The {@code float} primitive type. */
- public static final Type<Float> FLOAT = new Type<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);
-
- /** The {@code long} primitive type. */
- public static final Type<Long> LONG = new Type<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);
-
- /** 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);
-
- /** The {@code Object} type. */
- public static final Type<Object> OBJECT = new Type<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);
-
- private static final Map<Class<?>, Type<?>> PRIMITIVE_TO_TYPE
- = new HashMap<Class<?>, Type<?>>();
- static {
- PRIMITIVE_TO_TYPE.put(boolean.class, BOOLEAN);
- PRIMITIVE_TO_TYPE.put(byte.class, BYTE);
- PRIMITIVE_TO_TYPE.put(char.class, CHAR);
- PRIMITIVE_TO_TYPE.put(double.class, DOUBLE);
- PRIMITIVE_TO_TYPE.put(float.class, FLOAT);
- PRIMITIVE_TO_TYPE.put(int.class, INT);
- PRIMITIVE_TO_TYPE.put(long.class, LONG);
- PRIMITIVE_TO_TYPE.put(short.class, SHORT);
- PRIMITIVE_TO_TYPE.put(void.class, VOID);
- }
-
- final String name;
-
- /** cached converted values */
- final com.android.dx.rop.type.Type ropType;
- final CstType constant;
-
- Type(com.android.dx.rop.type.Type ropType) {
- this(ropType.getDescriptor(), ropType);
- }
-
- Type(String name, com.android.dx.rop.type.Type ropType) {
- if (name == null || ropType == null) {
- throw new NullPointerException();
- }
- this.name = name;
- this.ropType = ropType;
- this.constant = CstType.intern(ropType);
- }
-
- /**
- * @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> Type<T> get(Class<T> type) {
- if (type.isPrimitive()) {
- @SuppressWarnings("unchecked") // guarded by equals
- Type<T> result = (Type<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) {
- return new FieldId<T, V>(this, type, name);
- }
-
- public MethodId<T, Void> getConstructor(Type<?>... 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) {
- return new MethodId<T, R>(this, returnType, name, new TypeList(parameters));
- }
-
- public String getName() {
- return name;
- }
-
- @Override public boolean equals(Object o) {
- return o instanceof Type
- && ((Type) o).name.equals(name);
- }
-
- @Override public int hashCode() {
- return name.hashCode();
- }
-
- @Override public String toString() {
- return name;
- }
-}
diff --git a/dx/src/com/android/dx/gen/TypeList.java b/dx/src/com/android/dx/gen/TypeList.java
deleted file mode 100644
index e18ed4a28..000000000
--- a/dx/src/com/android/dx/gen/TypeList.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2011 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.android.dx.gen;
-
-import com.android.dx.rop.type.StdTypeList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * An immutable of types.
- */
-final class TypeList {
- final Type<?>[] types;
- final StdTypeList ropTypes;
-
- TypeList(Type<?>[] types) {
- this.types = types.clone();
- this.ropTypes = new StdTypeList(types.length);
- for (int i = 0; i < types.length; i++) {
- ropTypes.set(i, types[i].ropType);
- }
- }
-
- /**
- * Returns an immutable list.
- */
- public List<Type<?>> asList() {
- return Collections.unmodifiableList(Arrays.asList(types));
- }
-
- @Override public boolean equals(Object o) {
- return o instanceof TypeList && Arrays.equals(((TypeList) o).types, types);
- }
-
- @Override public int hashCode() {
- return Arrays.hashCode(types);
- }
-
- @Override public String toString() {
- StringBuilder result = new StringBuilder();
- for (int i = 0; i < types.length; i++) {
- if (i > 0) {
- result.append(", ");
- }
- result.append(types[i]);
- }
- return result.toString();
- }
-}