1579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson/*
2579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Copyright (C) 2011 The Android Open Source Project
3579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
4579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Licensed under the Apache License, Version 2.0 (the "License");
5579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * you may not use this file except in compliance with the License.
6579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * You may obtain a copy of the License at
7579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
8579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *      http://www.apache.org/licenses/LICENSE-2.0
9579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
10579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Unless required by applicable law or agreed to in writing, software
11579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS,
12579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * See the License for the specific language governing permissions and
14579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * limitations under the License.
15579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */
16579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
17579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonpackage com.google.dexmaker;
18579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
19579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.io.File;
20054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousefimport java.io.FilenameFilter;
21579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.io.IOException;
22579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.lang.reflect.Field;
23579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.lang.reflect.InvocationTargetException;
24579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.lang.reflect.Method;
255624228626d7cdf206de25a6981ba8107be61057Jesse Wilsonimport java.lang.reflect.Modifier;
26c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilsonimport static java.lang.reflect.Modifier.ABSTRACT;
2790699b97998f1582a921202fb909f17f9718d177Jesse Wilsonimport static java.lang.reflect.Modifier.FINAL;
28c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilsonimport static java.lang.reflect.Modifier.NATIVE;
2990699b97998f1582a921202fb909f17f9718d177Jesse Wilsonimport static java.lang.reflect.Modifier.PRIVATE;
3090699b97998f1582a921202fb909f17f9718d177Jesse Wilsonimport static java.lang.reflect.Modifier.PROTECTED;
3190699b97998f1582a921202fb909f17f9718d177Jesse Wilsonimport static java.lang.reflect.Modifier.PUBLIC;
3290699b97998f1582a921202fb909f17f9718d177Jesse Wilsonimport static java.lang.reflect.Modifier.STATIC;
335624228626d7cdf206de25a6981ba8107be61057Jesse Wilsonimport static java.lang.reflect.Modifier.SYNCHRONIZED;
34579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.util.Arrays;
35579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.util.List;
36579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.util.concurrent.Callable;
3790699b97998f1582a921202fb909f17f9718d177Jesse Wilsonimport junit.framework.TestCase;
38579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
39579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson/**
40579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * This generates a class named 'Generated' with one or more generated methods
41579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * and fields. In loads the generated class into the current VM and uses
42579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * reflection to invoke its methods.
43579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
44579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * <p>This test must run on a Dalvik VM.
45579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */
46ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilsonpublic final class DexMakerTest extends TestCase {
47ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson    private DexMaker dexMaker;
480e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson    private static TypeId<DexMakerTest> TEST_TYPE = TypeId.get(DexMakerTest.class);
490e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson    private static TypeId<?> INT_ARRAY = TypeId.get(int[].class);
500e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson    private static TypeId<boolean[]> BOOLEAN_ARRAY = TypeId.get(boolean[].class);
510e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson    private static TypeId<long[]> LONG_ARRAY = TypeId.get(long[].class);
520e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson    private static TypeId<Object[]> OBJECT_ARRAY = TypeId.get(Object[].class);
530e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson    private static TypeId<long[][]> LONG_2D_ARRAY = TypeId.get(long[][].class);
540e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson    private static TypeId<?> GENERATED = TypeId.get("LGenerated;");
550e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson    private static TypeId<Callable> CALLABLE = TypeId.get(Callable.class);
560e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson    private static MethodId<Callable, Object> CALL = CALLABLE.getMethod(TypeId.OBJECT, "call");
57579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
58579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    @Override protected void setUp() throws Exception {
59579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        super.setUp();
60579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        reset();
61579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
62579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
63579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
64579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * The generator is mutable. Calling reset creates a new empty generator.
65579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * This is necessary to generate multiple classes in the same test method.
66579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
67579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private void reset() {
68ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson        dexMaker = new DexMaker();
690e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        dexMaker.declare(GENERATED, "Generated.java", PUBLIC, TypeId.OBJECT);
70054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        clearDataDirectory();
71054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
72054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
73054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    private void clearDataDirectory() {
74054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        for (File f : getDataDirectory().listFiles()) {
75054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            if (f.getName().endsWith(".jar") || f.getName().endsWith(".dex")) {
76054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef                f.delete();
77054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            }
78054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        }
79579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
80579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
81579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testNewInstance() throws Exception {
82579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
83579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * public static Constructable call(long a, boolean b) {
84579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   Constructable result = new Constructable(a, b);
85579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   return result;
86579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * }
87579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
880e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        TypeId<Constructable> constructable = TypeId.get(Constructable.class);
89579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        MethodId<?, Constructable> methodId = GENERATED.getMethod(
900e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson                constructable, "call", TypeId.LONG, TypeId.BOOLEAN);
91ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson        Code code = dexMaker.declare(methodId, PUBLIC | STATIC);
920e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<Long> localA = code.getParameter(0, TypeId.LONG);
930e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<Boolean> localB = code.getParameter(1, TypeId.BOOLEAN);
94579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        MethodId<Constructable, Void> constructor
950e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson                = constructable.getConstructor(TypeId.LONG, TypeId.BOOLEAN);
96579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Local<Constructable> localResult = code.newLocal(constructable);
97579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.newInstance(localResult, constructor, localA, localB);
98579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.returnValue(localResult);
99579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
100579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Constructable constructed = (Constructable) getMethod().invoke(null, 5L, false);
101579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(5L, constructed.a);
102579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(false, constructed.b);
103579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
104579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
105579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class Constructable {
106579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private final long a;
107579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private final boolean b;
108579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public Constructable(long a, boolean b) {
109579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            this.a = a;
110579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            this.b = b;
111579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
112579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
113579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
114579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testVoidNoArgMemberMethod() throws Exception {
115579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
116579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * public void call() {
117579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * }
118579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
1190e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        MethodId<?, Void> methodId = GENERATED.getMethod(TypeId.VOID, "call");
120ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson        Code code = dexMaker.declare(methodId, PUBLIC);
121579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.returnVoid();
122579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
123579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        addDefaultConstructor();
124579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
125b3b96215f3dcbacb3f0d86780ac635cfc14ae9cfJesse Wilson        Class<?> generatedClass = generateAndLoad();
126579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Object instance = generatedClass.newInstance();
127579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method method = generatedClass.getMethod("call");
128579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        method.invoke(instance);
129579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
130579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
131579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testInvokeStatic() throws Exception {
132579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
133579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * public static int call(int a) {
134ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson         *   int result = DexMakerTest.staticMethod(a);
135579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   return result;
136579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * }
137579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
1380e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        MethodId<?, Integer> methodId = GENERATED.getMethod(TypeId.INT, "call", TypeId.INT);
139ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson        Code code = dexMaker.declare(methodId, PUBLIC | STATIC);
1400e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<Integer> localA = code.getParameter(0, TypeId.INT);
1410e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<Integer> localResult = code.newLocal(TypeId.INT);
142579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        MethodId<?, Integer> staticMethod
1430e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson                = TEST_TYPE.getMethod(TypeId.INT, "staticMethod", TypeId.INT);
144579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.invokeStatic(staticMethod, localResult, localA);
145579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.returnValue(localResult);
146579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
147579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(10, getMethod().invoke(null, 4));
148579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
149579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
150579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testCreateLocalMethodAsNull() throws Exception {
151579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
152579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * public void call(int value) {
153579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   Method method = null;
154579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * }
155579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
1560e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        MethodId<?, Void> methodId = GENERATED.getMethod(TypeId.VOID, "call", TypeId.INT);
1570e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        TypeId<Method> methodType = TypeId.get(Method.class);
158ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson        Code code = dexMaker.declare(methodId, PUBLIC);
159579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Local<Method> localMethod = code.newLocal(methodType);
160579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.loadConstant(localMethod, null);
161579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.returnVoid();
162579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
163579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        addDefaultConstructor();
164579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
165b3b96215f3dcbacb3f0d86780ac635cfc14ae9cfJesse Wilson        Class<?> generatedClass = generateAndLoad();
166579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Object instance = generatedClass.newInstance();
167579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method method = generatedClass.getMethod("call", int.class);
168579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        method.invoke(instance, 0);
169579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
170579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
171579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    @SuppressWarnings("unused") // called by generated code
172579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static int staticMethod(int a) {
173579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return a + 6;
174579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
175579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
176579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testInvokeVirtual() throws Exception {
177579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
178ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson         * public static int call(DexMakerTest test, int a) {
179579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   int result = test.virtualMethod(a);
180579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   return result;
181579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * }
182579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
1830e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        MethodId<?, Integer> methodId = GENERATED.getMethod(TypeId.INT, "call", TEST_TYPE, TypeId.INT);
184ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson        Code code = dexMaker.declare(methodId, PUBLIC | STATIC);
185ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson        Local<DexMakerTest> localInstance = code.getParameter(0, TEST_TYPE);
1860e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<Integer> localA = code.getParameter(1, TypeId.INT);
1870e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<Integer> localResult = code.newLocal(TypeId.INT);
188ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson        MethodId<DexMakerTest, Integer> virtualMethod
1890e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson                = TEST_TYPE.getMethod(TypeId.INT, "virtualMethod", TypeId.INT);
190579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.invokeVirtual(virtualMethod, localResult, localInstance, localA);
191579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.returnValue(localResult);
192579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
193579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(9, getMethod().invoke(null, this, 4));
194579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
195579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
196579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    @SuppressWarnings("unused") // called by generated code
197579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public int virtualMethod(int a) {
198579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return a + 5;
199579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
200579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
201579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public <G> void testInvokeDirect() throws Exception {
202579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
203579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * private int directMethod() {
204579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   int a = 5;
205579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   return a;
206579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * }
207579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *
208579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * public static int call(Generated g) {
209579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   int b = g.directMethod();
210579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   return b;
211579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * }
212579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
2130e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        TypeId<G> generated = TypeId.get("LGenerated;");
2140e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        MethodId<G, Integer> directMethodId = generated.getMethod(TypeId.INT, "directMethod");
215ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson        Code directCode = dexMaker.declare(directMethodId, PRIVATE);
216579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        directCode.getThis(generated); // 'this' is unused
2170e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<Integer> localA = directCode.newLocal(TypeId.INT);
218579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        directCode.loadConstant(localA, 5);
219579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        directCode.returnValue(localA);
220579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
2210e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        MethodId<G, Integer> methodId = generated.getMethod(TypeId.INT, "call", generated);
222ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson        Code code = dexMaker.declare(methodId, PUBLIC | STATIC);
2230e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<Integer> localB = code.newLocal(TypeId.INT);
224579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Local<G> localG = code.getParameter(0, generated);
225579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.invokeDirect(directMethodId, localB, localG);
226579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.returnValue(localB);
227579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
228579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        addDefaultConstructor();
229579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
230b3b96215f3dcbacb3f0d86780ac635cfc14ae9cfJesse Wilson        Class<?> generatedClass = generateAndLoad();
231579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Object instance = generatedClass.newInstance();
232579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method method = generatedClass.getMethod("call", generatedClass);
233579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(5, method.invoke(null, instance));
234579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
235579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
236579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public <G> void testInvokeSuper() throws Exception {
237579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
238579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * public int superHashCode() {
239579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   int result = super.hashCode();
240579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   return result;
241579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * }
242579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * public int hashCode() {
243579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   return 0;
244579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * }
245579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
2460e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        TypeId<G> generated = TypeId.get("LGenerated;");
2470e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        MethodId<Object, Integer> objectHashCode = TypeId.OBJECT.getMethod(TypeId.INT, "hashCode");
248ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson        Code superHashCode = dexMaker.declare(
2490e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson                GENERATED.getMethod(TypeId.INT, "superHashCode"), PUBLIC);
2500e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<Integer> localResult = superHashCode.newLocal(TypeId.INT);
251579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Local<G> localThis = superHashCode.getThis(generated);
252579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        superHashCode.invokeSuper(objectHashCode, localResult, localThis);
253579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        superHashCode.returnValue(localResult);
254579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
255ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson        Code generatedHashCode = dexMaker.declare(
2560e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson                GENERATED.getMethod(TypeId.INT, "hashCode"), PUBLIC);
2570e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<Integer> localZero = generatedHashCode.newLocal(TypeId.INT);
258579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        generatedHashCode.loadConstant(localZero, 0);
259579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        generatedHashCode.returnValue(localZero);
260579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
261579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        addDefaultConstructor();
262579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
263b3b96215f3dcbacb3f0d86780ac635cfc14ae9cfJesse Wilson        Class<?> generatedClass = generateAndLoad();
264579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Object instance = generatedClass.newInstance();
265579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method method = generatedClass.getMethod("superHashCode");
266579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(System.identityHashCode(instance), method.invoke(instance));
267579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
268579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
269579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testInvokeInterface() throws Exception {
270579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
271579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * public static Object call(Callable c) {
272579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   Object result = c.call();
273579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   return result;
274579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * }
275579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
2760e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        MethodId<?, Object> methodId = GENERATED.getMethod(TypeId.OBJECT, "call", CALLABLE);
277ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson        Code code = dexMaker.declare(methodId, PUBLIC | STATIC);
278579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Local<Callable> localC = code.getParameter(0, CALLABLE);
2790e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<Object> localResult = code.newLocal(TypeId.OBJECT);
280579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.invokeInterface(CALL, localResult, localC);
281579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.returnValue(localResult);
282579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
283579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Callable<Object> callable = new Callable<Object>() {
284579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            public Object call() throws Exception {
285579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                return "abc";
286579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
287579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        };
288579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("abc", getMethod().invoke(null, callable));
289579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
290579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
2915624228626d7cdf206de25a6981ba8107be61057Jesse Wilson    public void testInvokeVoidMethodIgnoresTargetLocal() throws Exception {
2925624228626d7cdf206de25a6981ba8107be61057Jesse Wilson        /*
2935624228626d7cdf206de25a6981ba8107be61057Jesse Wilson         * public static int call() {
2945624228626d7cdf206de25a6981ba8107be61057Jesse Wilson         *   int result = 5;
2955624228626d7cdf206de25a6981ba8107be61057Jesse Wilson         *   DexMakerTest.voidMethod();
2965624228626d7cdf206de25a6981ba8107be61057Jesse Wilson         *   return result;
2975624228626d7cdf206de25a6981ba8107be61057Jesse Wilson         * }
2985624228626d7cdf206de25a6981ba8107be61057Jesse Wilson         */
2995624228626d7cdf206de25a6981ba8107be61057Jesse Wilson        MethodId<?, Integer> methodId = GENERATED.getMethod(TypeId.INT, "call");
3005624228626d7cdf206de25a6981ba8107be61057Jesse Wilson        MethodId<?, Void> voidMethod = TEST_TYPE.getMethod(TypeId.VOID, "voidMethod");
3015624228626d7cdf206de25a6981ba8107be61057Jesse Wilson        Code code = dexMaker.declare(methodId, PUBLIC | STATIC);
3025624228626d7cdf206de25a6981ba8107be61057Jesse Wilson        Local<Integer> result = code.newLocal(TypeId.INT);
3035624228626d7cdf206de25a6981ba8107be61057Jesse Wilson        code.loadConstant(result, 5);
3045624228626d7cdf206de25a6981ba8107be61057Jesse Wilson        code.invokeStatic(voidMethod, null);
3055624228626d7cdf206de25a6981ba8107be61057Jesse Wilson        code.returnValue(result);
3065624228626d7cdf206de25a6981ba8107be61057Jesse Wilson
3075624228626d7cdf206de25a6981ba8107be61057Jesse Wilson        assertEquals(5, getMethod().invoke(null));
3085624228626d7cdf206de25a6981ba8107be61057Jesse Wilson    }
3095624228626d7cdf206de25a6981ba8107be61057Jesse Wilson
3105624228626d7cdf206de25a6981ba8107be61057Jesse Wilson    @SuppressWarnings("unused") // called by generated code
3115624228626d7cdf206de25a6981ba8107be61057Jesse Wilson    public static void voidMethod() {
3125624228626d7cdf206de25a6981ba8107be61057Jesse Wilson    }
3135624228626d7cdf206de25a6981ba8107be61057Jesse Wilson
314579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testParameterMismatch() throws Exception {
3150e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        TypeId<?>[] argTypes = {
3160e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson                TypeId.get(Integer.class), // should fail because the code specifies int
3170e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson                TypeId.OBJECT,
318579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        };
3190e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        MethodId<?, Integer> methodId = GENERATED.getMethod(TypeId.INT, "call", argTypes);
320ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson        Code code = dexMaker.declare(methodId, PUBLIC | STATIC);
321579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        try {
3220e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson            code.getParameter(0, TypeId.INT);
323579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (IllegalArgumentException e) {
324579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
325579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        try {
3260e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson            code.getParameter(2, TypeId.INT);
327579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (IndexOutOfBoundsException e) {
328579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
329579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
330579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
331579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testInvokeTypeSafety() throws Exception {
332579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
333ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson         * public static boolean call(DexMakerTest test) {
334579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   CharSequence cs = test.toString();
335579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   boolean result = cs.equals(test);
336579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   return result;
337579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * }
338579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
3390e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        MethodId<?, Boolean> methodId = GENERATED.getMethod(TypeId.BOOLEAN, "call", TEST_TYPE);
340ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson        Code code = dexMaker.declare(methodId, PUBLIC | STATIC);
341ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson        Local<DexMakerTest> localTest = code.getParameter(0, TEST_TYPE);
3420e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        TypeId<CharSequence> charSequenceType = TypeId.get(CharSequence.class);
3430e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        MethodId<Object, String> objectToString
3440e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson                = TypeId.OBJECT.getMethod(TypeId.STRING, "toString");
345579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        MethodId<Object, Boolean> objectEquals
3460e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson                = TypeId.OBJECT.getMethod(TypeId.BOOLEAN, "equals", TypeId.OBJECT);
347579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Local<CharSequence> localCs = code.newLocal(charSequenceType);
3480e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<Boolean> localResult = code.newLocal(TypeId.BOOLEAN);
349579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.invokeVirtual(objectToString, localCs, localTest);
350579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.invokeVirtual(objectEquals, localResult, localCs, localTest);
351579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.returnValue(localResult);
352579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
353579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(false, getMethod().invoke(null, this));
354579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
355579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
356579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testReturnTypeMismatch() {
3570e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        MethodId<?, String> methodId = GENERATED.getMethod(TypeId.STRING, "call");
358ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson        Code code = dexMaker.declare(methodId, PUBLIC | STATIC);
359579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        try {
3600e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson            code.returnValue(code.newLocal(TypeId.BOOLEAN));
361579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            fail();
362579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (IllegalArgumentException expected) {
363579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
364579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        try {
365579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            code.returnVoid();
366579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            fail();
367579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (IllegalArgumentException expected) {
368579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
369579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
370579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
371579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testDeclareStaticFields() throws Exception {
372579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
373579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * class Generated {
374579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   public static int a;
375579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   protected static Object b;
376579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * }
377579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
3780e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        dexMaker.declare(GENERATED.getField(TypeId.INT, "a"), PUBLIC | STATIC, 3);
3790e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        dexMaker.declare(GENERATED.getField(TypeId.OBJECT, "b"), PROTECTED | STATIC, null);
380b3b96215f3dcbacb3f0d86780ac635cfc14ae9cfJesse Wilson        Class<?> generatedClass = generateAndLoad();
381579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
382579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Field a = generatedClass.getField("a");
383579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(int.class, a.getType());
384579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(3, a.get(null));
385579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
386579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Field b = generatedClass.getDeclaredField("b");
387579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(Object.class, b.getType());
388579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        b.setAccessible(true);
389579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(null, b.get(null));
390579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
391579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
392579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testDeclareInstanceFields() throws Exception {
393579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
394579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * class Generated {
395579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   public int a;
396579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   protected Object b;
397579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * }
398579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
3990e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        dexMaker.declare(GENERATED.getField(TypeId.INT, "a"), PUBLIC, null);
4000e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        dexMaker.declare(GENERATED.getField(TypeId.OBJECT, "b"), PROTECTED, null);
401579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
402579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        addDefaultConstructor();
403579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
404b3b96215f3dcbacb3f0d86780ac635cfc14ae9cfJesse Wilson        Class<?> generatedClass = generateAndLoad();
405579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Object instance = generatedClass.newInstance();
406579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
407579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Field a = generatedClass.getField("a");
408579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(int.class, a.getType());
409579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0, a.get(instance));
410579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
411579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Field b = generatedClass.getDeclaredField("b");
412579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(Object.class, b.getType());
413579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        b.setAccessible(true);
414579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(null, b.get(instance));
415579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
416579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
417579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
418579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Declare a constructor that takes an int parameter and assigns it to a
419579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * field.
420579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
421579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public <G> void testDeclareConstructor() throws Exception {
422579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
423579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * class Generated {
424579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   public final int a;
425579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   public Generated(int a) {
426579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *     this.a = a;
427579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   }
428579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * }
429579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
4300e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        TypeId<G> generated = TypeId.get("LGenerated;");
4310e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        FieldId<G, Integer> fieldId = generated.getField(TypeId.INT, "a");
432ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson        dexMaker.declare(fieldId, PUBLIC | FINAL, null);
4330e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        MethodId<?, Void> constructor = GENERATED.getConstructor(TypeId.INT);
434c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson        Code code = dexMaker.declare(constructor, PUBLIC);
435579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Local<G> thisRef = code.getThis(generated);
4360e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<Integer> parameter = code.getParameter(0, TypeId.INT);
4370e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        code.invokeDirect(TypeId.OBJECT.getConstructor(), null, thisRef);
438579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.iput(fieldId, thisRef, parameter);
439579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.returnVoid();
440579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
441b3b96215f3dcbacb3f0d86780ac635cfc14ae9cfJesse Wilson        Class<?> generatedClass = generateAndLoad();
442579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Field a = generatedClass.getField("a");
443579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Object instance = generatedClass.getConstructor(int.class).newInstance(0xabcd);
444579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0xabcd, a.get(instance));
445579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
446579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
4475624228626d7cdf206de25a6981ba8107be61057Jesse Wilson    public void testReturnType() throws Exception {
448579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        testReturnType(boolean.class, true);
449579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        testReturnType(byte.class, (byte) 5);
450579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        testReturnType(char.class, 'E');
451579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        testReturnType(double.class, 5.0);
452579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        testReturnType(float.class, 5.0f);
453579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        testReturnType(int.class, 5);
454579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        testReturnType(long.class, 5L);
455579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        testReturnType(short.class, (short) 5);
456579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        testReturnType(void.class, null);
457579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        testReturnType(String.class, "foo");
458579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        testReturnType(Class.class, List.class);
459579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
460579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
461579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private <T> void testReturnType(Class<T> javaType, T value) throws Exception {
462579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
463579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * public int call() {
464579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   int a = 5;
465579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   return a;
466579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * }
467579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
468579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        reset();
4690e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        TypeId<T> returnType = TypeId.get(javaType);
470ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson        Code code = dexMaker.declare(GENERATED.getMethod(returnType, "call"), PUBLIC | STATIC);
471579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (value != null) {
472579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            Local<T> i = code.newLocal(returnType);
473579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            code.loadConstant(i, value);
474579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            code.returnValue(i);
475579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } else {
476579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            code.returnVoid();
477579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
478579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
479b3b96215f3dcbacb3f0d86780ac635cfc14ae9cfJesse Wilson        Class<?> generatedClass = generateAndLoad();
480579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method method = generatedClass.getMethod("call");
481579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(javaType, method.getReturnType());
482579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(value, method.invoke(null));
483579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
484579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
485579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testBranching() throws Exception {
486579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method lt = branchingMethod(Comparison.LT);
487579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(Boolean.TRUE, lt.invoke(null, 1, 2));
488579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(Boolean.FALSE, lt.invoke(null, 1, 1));
489579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(Boolean.FALSE, lt.invoke(null, 2, 1));
490579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
491579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method le = branchingMethod(Comparison.LE);
492579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(Boolean.TRUE, le.invoke(null, 1, 2));
493579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(Boolean.TRUE, le.invoke(null, 1, 1));
494579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(Boolean.FALSE, le.invoke(null, 2, 1));
495579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
496579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method eq = branchingMethod(Comparison.EQ);
497579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(Boolean.FALSE, eq.invoke(null, 1, 2));
498579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(Boolean.TRUE, eq.invoke(null, 1, 1));
499579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(Boolean.FALSE, eq.invoke(null, 2, 1));
500579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
501579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method ge = branchingMethod(Comparison.GE);
502579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(Boolean.FALSE, ge.invoke(null, 1, 2));
503579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(Boolean.TRUE, ge.invoke(null, 1, 1));
504579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(Boolean.TRUE, ge.invoke(null, 2, 1));
505579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
506579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method gt = branchingMethod(Comparison.GT);
507579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(Boolean.FALSE, gt.invoke(null, 1, 2));
508579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(Boolean.FALSE, gt.invoke(null, 1, 1));
509579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(Boolean.TRUE, gt.invoke(null, 2, 1));
510579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
511579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method ne = branchingMethod(Comparison.NE);
512579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(Boolean.TRUE, ne.invoke(null, 1, 2));
513579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(Boolean.FALSE, ne.invoke(null, 1, 1));
514579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(Boolean.TRUE, ne.invoke(null, 2, 1));
515579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
516579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
517579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private Method branchingMethod(Comparison comparison) throws Exception {
518579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
519579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * public static boolean call(int localA, int localB) {
520579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   if (a comparison b) {
521579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *     return true;
522579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   }
523579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   return false;
524579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * }
525579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
526579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        reset();
527579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        MethodId<?, Boolean> methodId = GENERATED.getMethod(
5280e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson                TypeId.BOOLEAN, "call", TypeId.INT, TypeId.INT);
529ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson        Code code = dexMaker.declare(methodId, PUBLIC | STATIC);
5300e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<Integer> localA = code.getParameter(0, TypeId.INT);
5310e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<Integer> localB = code.getParameter(1, TypeId.INT);
5320e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<Boolean> result = code.newLocal(TypeId.get(boolean.class));
53323abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson        Label afterIf = new Label();
53423abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson        Label ifBody = new Label();
5350e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        code.compare(comparison, ifBody, localA, localB);
536579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.jump(afterIf);
537579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
538579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.mark(ifBody);
539579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.loadConstant(result, true);
540579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.returnValue(result);
541579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
542579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.mark(afterIf);
543579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.loadConstant(result, false);
544579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.returnValue(result);
545579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return getMethod();
546579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
547579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
548579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testCastIntegerToInteger() throws Exception {
549579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method intToLong = numericCastingMethod(int.class, long.class);
550579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0x0000000000000000L, intToLong.invoke(null, 0x00000000));
551579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0x000000007fffffffL, intToLong.invoke(null, 0x7fffffff));
552579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0xffffffff80000000L, intToLong.invoke(null, 0x80000000));
553579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0xffffffffffffffffL, intToLong.invoke(null, 0xffffffff));
554579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
555579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method longToInt = numericCastingMethod(long.class, int.class);
556579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0x1234abcd, longToInt.invoke(null, 0x000000001234abcdL));
557579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0x1234abcd, longToInt.invoke(null, 0x123456781234abcdL));
558579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0x1234abcd, longToInt.invoke(null, 0xffffffff1234abcdL));
559579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
560579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method intToShort = numericCastingMethod(int.class, short.class);
561579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals((short) 0x1234, intToShort.invoke(null, 0x00001234));
562579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals((short) 0x1234, intToShort.invoke(null, 0xabcd1234));
563579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals((short) 0x1234, intToShort.invoke(null, 0xffff1234));
564579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
565579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method intToChar = numericCastingMethod(int.class, char.class);
566579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals((char) 0x1234, intToChar.invoke(null, 0x00001234));
567579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals((char) 0x1234, intToChar.invoke(null, 0xabcd1234));
568579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals((char) 0x1234, intToChar.invoke(null, 0xffff1234));
569579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
570579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method intToByte = numericCastingMethod(int.class, byte.class);
571579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals((byte) 0x34, intToByte.invoke(null, 0x00000034));
572579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals((byte) 0x34, intToByte.invoke(null, 0xabcd1234));
573579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals((byte) 0x34, intToByte.invoke(null, 0xffffff34));
574579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
575579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
576579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testCastIntegerToFloatingPoint() throws Exception {
577579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method intToFloat = numericCastingMethod(int.class, float.class);
578579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0.0f, intToFloat.invoke(null, 0));
579579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(-1.0f, intToFloat.invoke(null, -1));
580579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(16777216f, intToFloat.invoke(null, 16777216));
581579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(16777216f, intToFloat.invoke(null, 16777217)); // precision
582579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
583579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method intToDouble = numericCastingMethod(int.class, double.class);
584579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0.0, intToDouble.invoke(null, 0));
585579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(-1.0, intToDouble.invoke(null, -1));
586579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(16777216.0, intToDouble.invoke(null, 16777216));
587579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(16777217.0, intToDouble.invoke(null, 16777217));
588579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
589579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method longToFloat = numericCastingMethod(long.class, float.class);
590579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0.0f, longToFloat.invoke(null, 0L));
591579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(-1.0f, longToFloat.invoke(null, -1L));
592579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(16777216f, longToFloat.invoke(null, 16777216L));
593579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(16777216f, longToFloat.invoke(null, 16777217L));
594579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
595579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method longToDouble = numericCastingMethod(long.class, double.class);
596579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0.0, longToDouble.invoke(null, 0L));
597579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(-1.0, longToDouble.invoke(null, -1L));
598579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(9007199254740992.0, longToDouble.invoke(null, 9007199254740992L));
599579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(9007199254740992.0, longToDouble.invoke(null, 9007199254740993L)); // precision
600579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
601579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
602579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testCastFloatingPointToInteger() throws Exception {
603579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method floatToInt = numericCastingMethod(float.class, int.class);
604579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0, floatToInt.invoke(null, 0.0f));
605579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(-1, floatToInt.invoke(null, -1.0f));
606579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(Integer.MAX_VALUE, floatToInt.invoke(null, 10e15f));
607579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0, floatToInt.invoke(null, 0.5f));
608579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(Integer.MIN_VALUE, floatToInt.invoke(null, Float.NEGATIVE_INFINITY));
609579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0, floatToInt.invoke(null, Float.NaN));
610579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
611579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method floatToLong = numericCastingMethod(float.class, long.class);
612579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0L, floatToLong.invoke(null, 0.0f));
613579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(-1L, floatToLong.invoke(null, -1.0f));
614579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(10000000272564224L, floatToLong.invoke(null, 10e15f));
615579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0L, floatToLong.invoke(null, 0.5f));
616579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(Long.MIN_VALUE, floatToLong.invoke(null, Float.NEGATIVE_INFINITY));
617579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0L, floatToLong.invoke(null, Float.NaN));
618579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
619579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method doubleToInt = numericCastingMethod(double.class, int.class);
620579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0, doubleToInt.invoke(null, 0.0));
621579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(-1, doubleToInt.invoke(null, -1.0));
622579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(Integer.MAX_VALUE, doubleToInt.invoke(null, 10e15));
623579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0, doubleToInt.invoke(null, 0.5));
624579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(Integer.MIN_VALUE, doubleToInt.invoke(null, Double.NEGATIVE_INFINITY));
625579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0, doubleToInt.invoke(null, Double.NaN));
626579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
627579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method doubleToLong = numericCastingMethod(double.class, long.class);
628579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0L, doubleToLong.invoke(null, 0.0));
629579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(-1L, doubleToLong.invoke(null, -1.0));
630579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(10000000000000000L, doubleToLong.invoke(null, 10e15));
631579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0L, doubleToLong.invoke(null, 0.5));
632579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(Long.MIN_VALUE, doubleToLong.invoke(null, Double.NEGATIVE_INFINITY));
633579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0L, doubleToLong.invoke(null, Double.NaN));
634579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
635579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
636579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testCastFloatingPointToFloatingPoint() throws Exception {
637579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method floatToDouble = numericCastingMethod(float.class, double.class);
638579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0.0, floatToDouble.invoke(null, 0.0f));
639579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(-1.0, floatToDouble.invoke(null, -1.0f));
640579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0.5, floatToDouble.invoke(null, 0.5f));
641579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(Double.NEGATIVE_INFINITY, floatToDouble.invoke(null, Float.NEGATIVE_INFINITY));
642579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(Double.NaN, floatToDouble.invoke(null, Float.NaN));
643579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
644579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method doubleToFloat = numericCastingMethod(double.class, float.class);
645579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0.0f, doubleToFloat.invoke(null, 0.0));
646579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(-1.0f, doubleToFloat.invoke(null, -1.0));
647579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0.5f, doubleToFloat.invoke(null, 0.5));
648579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(Float.NEGATIVE_INFINITY, doubleToFloat.invoke(null, Double.NEGATIVE_INFINITY));
649579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(Float.NaN, doubleToFloat.invoke(null, Double.NaN));
650579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
651579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
652579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private Method numericCastingMethod(Class<?> source, Class<?> target)
653579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throws Exception {
654579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
655579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * public static short call(int source) {
656579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   short casted = (short) source;
657579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   return casted;
658579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * }
659579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
660579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        reset();
6610e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        TypeId<?> sourceType = TypeId.get(source);
6620e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        TypeId<?> targetType = TypeId.get(target);
663579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        MethodId<?, ?> methodId = GENERATED.getMethod(targetType, "call", sourceType);
664ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson        Code code = dexMaker.declare(methodId, PUBLIC | STATIC);
665579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Local<?> localSource = code.getParameter(0, sourceType);
666579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Local<?> localCasted = code.newLocal(targetType);
66797b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson        code.cast(localCasted, localSource);
668579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.returnValue(localCasted);
669579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return getMethod();
670579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
671579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
672579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testNot() throws Exception {
673579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method notInteger = notMethod(int.class);
674579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0xffffffff, notInteger.invoke(null, 0x00000000));
675579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0x00000000, notInteger.invoke(null, 0xffffffff));
676579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0xedcba987, notInteger.invoke(null, 0x12345678));
677579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
678579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method notLong = notMethod(long.class);
679579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0xffffffffffffffffL, notLong.invoke(null, 0x0000000000000000L));
680579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0x0000000000000000L, notLong.invoke(null, 0xffffffffffffffffL));
681579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0x98765432edcba987L, notLong.invoke(null, 0x6789abcd12345678L));
682579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
683579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
684579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private <T> Method notMethod(Class<T> source) throws Exception {
685579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
686579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * public static short call(int source) {
687579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   source = ~source;
688579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   return not;
689579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * }
690579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
691579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        reset();
6920e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        TypeId<T> valueType = TypeId.get(source);
693579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        MethodId<?, T> methodId = GENERATED.getMethod(valueType, "call", valueType);
694ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson        Code code = dexMaker.declare(methodId, PUBLIC | STATIC);
695579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Local<T> localSource = code.getParameter(0, valueType);
696b0f6ea8cec29bd1b2453e8fd15d9c6f65ca3ea2cJesse Wilson        code.op(UnaryOp.NOT, localSource, localSource);
697579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.returnValue(localSource);
698579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return getMethod();
699579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
700579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
701579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testNegate() throws Exception {
702579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method negateInteger = negateMethod(int.class);
703579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0, negateInteger.invoke(null, 0));
704579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(-1, negateInteger.invoke(null, 1));
705579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(Integer.MIN_VALUE, negateInteger.invoke(null, Integer.MIN_VALUE));
706579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
707579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method negateLong = negateMethod(long.class);
708579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0L, negateLong.invoke(null, 0));
709579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(-1L, negateLong.invoke(null, 1));
710579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(Long.MIN_VALUE, negateLong.invoke(null, Long.MIN_VALUE));
711579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
712579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method negateFloat = negateMethod(float.class);
713579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(-0.0f, negateFloat.invoke(null, 0.0f));
714579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(-1.0f, negateFloat.invoke(null, 1.0f));
715579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(Float.NaN, negateFloat.invoke(null, Float.NaN));
716579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(Float.POSITIVE_INFINITY, negateFloat.invoke(null, Float.NEGATIVE_INFINITY));
717579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
718579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method negateDouble = negateMethod(double.class);
719579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(-0.0, negateDouble.invoke(null, 0.0));
720579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(-1.0, negateDouble.invoke(null, 1.0));
721579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(Double.NaN, negateDouble.invoke(null, Double.NaN));
722579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(Double.POSITIVE_INFINITY, negateDouble.invoke(null, Double.NEGATIVE_INFINITY));
723579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
724579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
725579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private <T> Method negateMethod(Class<T> source) throws Exception {
726579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
727579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * public static short call(int source) {
728579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   source = -source;
729579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   return not;
730579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * }
731579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
732579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        reset();
7330e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        TypeId<T> valueType = TypeId.get(source);
734579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        MethodId<?, T> methodId = GENERATED.getMethod(valueType, "call", valueType);
735ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson        Code code = dexMaker.declare(methodId, PUBLIC | STATIC);
736579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Local<T> localSource = code.getParameter(0, valueType);
737b0f6ea8cec29bd1b2453e8fd15d9c6f65ca3ea2cJesse Wilson        code.op(UnaryOp.NEGATE, localSource, localSource);
738579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.returnValue(localSource);
739579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return getMethod();
740579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
741579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
742579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testIntBinaryOps() throws Exception {
74395689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        Method add = binaryOpMethod(int.class, int.class, BinaryOp.ADD);
744579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(79, add.invoke(null, 75, 4));
745579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
74695689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        Method subtract = binaryOpMethod(int.class, int.class, BinaryOp.SUBTRACT);
747579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(71, subtract.invoke(null, 75, 4));
748579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
74995689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        Method multiply = binaryOpMethod(int.class, int.class, BinaryOp.MULTIPLY);
750579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(300, multiply.invoke(null, 75, 4));
751579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
75295689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        Method divide = binaryOpMethod(int.class, int.class, BinaryOp.DIVIDE);
753579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(18, divide.invoke(null, 75, 4));
754579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        try {
755579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            divide.invoke(null, 75, 0);
756579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            fail();
757579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (InvocationTargetException expected) {
758579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            assertEquals(ArithmeticException.class, expected.getCause().getClass());
759579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
760579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
76195689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        Method remainder = binaryOpMethod(int.class, int.class, BinaryOp.REMAINDER);
762579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(3, remainder.invoke(null, 75, 4));
763579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        try {
764579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            remainder.invoke(null, 75, 0);
765579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            fail();
766579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (InvocationTargetException expected) {
767579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            assertEquals(ArithmeticException.class, expected.getCause().getClass());
768579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
769579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
77095689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        Method and = binaryOpMethod(int.class, int.class, BinaryOp.AND);
771579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0xff000000, and.invoke(null, 0xff00ff00, 0xffff0000));
772579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
77395689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        Method or = binaryOpMethod(int.class, int.class, BinaryOp.OR);
774579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0xffffff00, or.invoke(null, 0xff00ff00, 0xffff0000));
775579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
77695689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        Method xor = binaryOpMethod(int.class, int.class, BinaryOp.XOR);
777579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0x00ffff00, xor.invoke(null, 0xff00ff00, 0xffff0000));
778579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
77995689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        Method shiftLeft = binaryOpMethod(int.class, int.class, BinaryOp.SHIFT_LEFT);
780579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0xcd123400, shiftLeft.invoke(null, 0xabcd1234, 8));
781579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
78295689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        Method shiftRight = binaryOpMethod(int.class, int.class, BinaryOp.SHIFT_RIGHT);
783579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0xffabcd12, shiftRight.invoke(null, 0xabcd1234, 8));
784579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
785579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method unsignedShiftRight = binaryOpMethod(int.class,
78695689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy                int.class, BinaryOp.UNSIGNED_SHIFT_RIGHT);
787579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0x00abcd12, unsignedShiftRight.invoke(null, 0xabcd1234, 8));
788579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
789579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
790579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testLongBinaryOps() throws Exception {
79195689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        Method add = binaryOpMethod(long.class, long.class, BinaryOp.ADD);
79295689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        assertEquals(30000000079L, add.invoke(null, 10000000075L, 20000000004L));
793579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
79495689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        Method subtract = binaryOpMethod(long.class, long.class, BinaryOp.SUBTRACT);
79595689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        assertEquals(20000000071L, subtract.invoke(null, 30000000075L, 10000000004L));
796579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
79795689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        Method multiply = binaryOpMethod(long.class, long.class, BinaryOp.MULTIPLY);
79895689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        assertEquals(-8742552812415203028L, multiply.invoke(null, 30000000075L, 20000000004L));
799579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
80095689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        Method divide = binaryOpMethod(long.class, long.class, BinaryOp.DIVIDE);
80195689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        assertEquals(-2L, divide.invoke(null, -8742552812415203028L, 4142552812415203028L));
802579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        try {
80395689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy            divide.invoke(null, -8742552812415203028L, 0L);
804579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            fail();
805579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (InvocationTargetException expected) {
806579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            assertEquals(ArithmeticException.class, expected.getCause().getClass());
807579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
808579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
80995689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        Method remainder = binaryOpMethod(long.class, long.class, BinaryOp.REMAINDER);
81095689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        assertEquals(10000000004L, remainder.invoke(null, 30000000079L, 20000000075L));
811579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        try {
81295689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy            remainder.invoke(null, 30000000079L, 0L);
813579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            fail();
814579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (InvocationTargetException expected) {
815579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            assertEquals(ArithmeticException.class, expected.getCause().getClass());
816579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
817579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
81895689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        Method and = binaryOpMethod(long.class, long.class, BinaryOp.AND);
819579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0xff00ff0000000000L,
820579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                and.invoke(null, 0xff00ff00ff00ff00L, 0xffffffff00000000L));
821579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
82295689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        Method or = binaryOpMethod(long.class, long.class, BinaryOp.OR);
823579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0xffffffffff00ff00L,
824579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                or.invoke(null, 0xff00ff00ff00ff00L, 0xffffffff00000000L));
825579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
82695689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        Method xor = binaryOpMethod(long.class, long.class, BinaryOp.XOR);
827579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0x00ff00ffff00ff00L,
828579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                xor.invoke(null, 0xff00ff00ff00ff00L, 0xffffffff00000000L));
829579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
83095689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        Method shiftLeft = binaryOpMethod(long.class, int.class, BinaryOp.SHIFT_LEFT);
83195689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        assertEquals(0xcdef012345678900L, shiftLeft.invoke(null, 0xabcdef0123456789L, 8));
832579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
83395689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        Method shiftRight = binaryOpMethod(long.class, int.class, BinaryOp.SHIFT_RIGHT);
83495689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        assertEquals(0xffabcdef01234567L, shiftRight.invoke(null, 0xabcdef0123456789L, 8));
835579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
83695689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        Method unsignedShiftRight = binaryOpMethod(
83795689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy                long.class, int.class, BinaryOp.UNSIGNED_SHIFT_RIGHT);
83895689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        assertEquals(0x00abcdef01234567L, unsignedShiftRight.invoke(null, 0xabcdef0123456789L, 8));
839579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
840579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
841579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testFloatBinaryOps() throws Exception {
84295689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        Method add = binaryOpMethod(float.class, float.class, BinaryOp.ADD);
843579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(6.75f, add.invoke(null, 5.5f, 1.25f));
844579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
84595689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        Method subtract = binaryOpMethod(float.class, float.class, BinaryOp.SUBTRACT);
846579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(4.25f, subtract.invoke(null, 5.5f, 1.25f));
847579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
84895689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        Method multiply = binaryOpMethod(float.class, float.class, BinaryOp.MULTIPLY);
849579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(6.875f, multiply.invoke(null, 5.5f, 1.25f));
850579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
85195689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        Method divide = binaryOpMethod(float.class, float.class, BinaryOp.DIVIDE);
852579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(4.4f, divide.invoke(null, 5.5f, 1.25f));
853579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(Float.POSITIVE_INFINITY, divide.invoke(null, 5.5f, 0.0f));
854579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
85595689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        Method remainder = binaryOpMethod(float.class, float.class, BinaryOp.REMAINDER);
856579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0.5f, remainder.invoke(null, 5.5f, 1.25f));
857579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(Float.NaN, remainder.invoke(null, 5.5f, 0.0f));
858579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
859579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
860579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testDoubleBinaryOps() throws Exception {
86195689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        Method add = binaryOpMethod(double.class, double.class, BinaryOp.ADD);
862579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(6.75, add.invoke(null, 5.5, 1.25));
863579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
86495689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        Method subtract = binaryOpMethod(double.class, double.class, BinaryOp.SUBTRACT);
865579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(4.25, subtract.invoke(null, 5.5, 1.25));
866579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
86795689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        Method multiply = binaryOpMethod(double.class, double.class, BinaryOp.MULTIPLY);
868579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(6.875, multiply.invoke(null, 5.5, 1.25));
869579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
87095689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        Method divide = binaryOpMethod(double.class, double.class, BinaryOp.DIVIDE);
871579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(4.4, divide.invoke(null, 5.5, 1.25));
872579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(Double.POSITIVE_INFINITY, divide.invoke(null, 5.5, 0.0));
873579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
87495689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        Method remainder = binaryOpMethod(double.class, double.class, BinaryOp.REMAINDER);
875579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0.5, remainder.invoke(null, 5.5, 1.25));
876579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(Double.NaN, remainder.invoke(null, 5.5, 0.0));
877579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
878579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
87995689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy    private <T1, T2> Method binaryOpMethod(
88095689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy            Class<T1> valueAClass, Class<T2> valueBClass, BinaryOp op) throws Exception {
881579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
882579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * public static int binaryOp(int a, int b) {
883579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   int result = a + b;
884579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   return result;
885579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * }
886579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
887579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        reset();
88895689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        TypeId<T1> valueAType = TypeId.get(valueAClass);
88995689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        TypeId<T2> valueBType = TypeId.get(valueBClass);
89095689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        MethodId<?, T1> methodId = GENERATED.getMethod(valueAType, "call", valueAType, valueBType);
891ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson        Code code = dexMaker.declare(methodId, PUBLIC | STATIC);
89295689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        Local<T1> localA = code.getParameter(0, valueAType);
89395689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        Local<T2> localB = code.getParameter(1, valueBType);
89495689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy        Local<T1> localResult = code.newLocal(valueAType);
895579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.op(op, localResult, localA, localB);
896579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.returnValue(localResult);
897579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return getMethod();
898579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
899579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
900579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testReadAndWriteInstanceFields() throws Exception {
901579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Instance instance = new Instance();
902579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
903579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method intSwap = instanceSwapMethod(int.class, "intValue");
904579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        instance.intValue = 5;
905579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(5, intSwap.invoke(null, instance, 10));
906579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(10, instance.intValue);
907579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
908579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method longSwap = instanceSwapMethod(long.class, "longValue");
909579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        instance.longValue = 500L;
910579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(500L, longSwap.invoke(null, instance, 1234L));
911579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(1234L, instance.longValue);
912579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
913579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method booleanSwap = instanceSwapMethod(boolean.class, "booleanValue");
914579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        instance.booleanValue = false;
915579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(false, booleanSwap.invoke(null, instance, true));
916579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(true, instance.booleanValue);
917579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
918579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method floatSwap = instanceSwapMethod(float.class, "floatValue");
919579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        instance.floatValue = 1.5f;
920579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(1.5f, floatSwap.invoke(null, instance, 0.5f));
921579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0.5f, instance.floatValue);
922579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
923579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method doubleSwap = instanceSwapMethod(double.class, "doubleValue");
924579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        instance.doubleValue = 155.5;
925579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(155.5, doubleSwap.invoke(null, instance, 266.6));
926579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(266.6, instance.doubleValue);
927579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
928579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method objectSwap = instanceSwapMethod(Object.class, "objectValue");
929579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        instance.objectValue = "before";
930579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("before", objectSwap.invoke(null, instance, "after"));
931579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("after", instance.objectValue);
932579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
933579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method byteSwap = instanceSwapMethod(byte.class, "byteValue");
934579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        instance.byteValue = 0x35;
935579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals((byte) 0x35, byteSwap.invoke(null, instance, (byte) 0x64));
936579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals((byte) 0x64, instance.byteValue);
937579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
938579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method charSwap = instanceSwapMethod(char.class, "charValue");
939579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        instance.charValue = 'A';
940579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals('A', charSwap.invoke(null, instance, 'B'));
941579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals('B', instance.charValue);
942579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
943579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method shortSwap = instanceSwapMethod(short.class, "shortValue");
944579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        instance.shortValue = (short) 0xabcd;
945579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals((short) 0xabcd, shortSwap.invoke(null, instance, (short) 0x1234));
946579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals((short) 0x1234, instance.shortValue);
947579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
948579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
949579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public class Instance {
950579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public int intValue;
951579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public long longValue;
952579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public float floatValue;
953579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public double doubleValue;
954579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public Object objectValue;
955579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public boolean booleanValue;
956579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public byte byteValue;
957579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public char charValue;
958579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public short shortValue;
959579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
960579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
961579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private <V> Method instanceSwapMethod(
962579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            Class<V> valueClass, String fieldName) throws Exception {
963579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
964579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * public static int call(Instance instance, int newValue) {
965579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   int oldValue = instance.intValue;
966579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   instance.intValue = newValue;
967579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   return oldValue;
968579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * }
969579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
970579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        reset();
9710e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        TypeId<V> valueType = TypeId.get(valueClass);
9720e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        TypeId<Instance> objectType = TypeId.get(Instance.class);
973579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        FieldId<Instance, V> fieldId = objectType.getField(valueType, fieldName);
974579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        MethodId<?, V> methodId = GENERATED.getMethod(valueType, "call", objectType, valueType);
975ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson        Code code = dexMaker.declare(methodId, PUBLIC | STATIC);
976579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Local<Instance> localInstance = code.getParameter(0, objectType);
977579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Local<V> localNewValue = code.getParameter(1, valueType);
978579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Local<V> localOldValue = code.newLocal(valueType);
9790e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        code.iget(fieldId, localOldValue, localInstance);
980579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.iput(fieldId, localInstance, localNewValue);
981579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.returnValue(localOldValue);
982579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return getMethod();
983579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
984579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
985579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testReadAndWriteStaticFields() throws Exception {
986579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method intSwap = staticSwapMethod(int.class, "intValue");
987579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Static.intValue = 5;
988579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(5, intSwap.invoke(null, 10));
989579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(10, Static.intValue);
990579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
991579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method longSwap = staticSwapMethod(long.class, "longValue");
992579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Static.longValue = 500L;
993579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(500L, longSwap.invoke(null, 1234L));
994579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(1234L, Static.longValue);
995579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
996579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method booleanSwap = staticSwapMethod(boolean.class, "booleanValue");
997579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Static.booleanValue = false;
998579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(false, booleanSwap.invoke(null, true));
999579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(true, Static.booleanValue);
1000579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1001579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method floatSwap = staticSwapMethod(float.class, "floatValue");
1002579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Static.floatValue = 1.5f;
1003579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(1.5f, floatSwap.invoke(null, 0.5f));
1004579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0.5f, Static.floatValue);
1005579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1006579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method doubleSwap = staticSwapMethod(double.class, "doubleValue");
1007579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Static.doubleValue = 155.5;
1008579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(155.5, doubleSwap.invoke(null, 266.6));
1009579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(266.6, Static.doubleValue);
1010579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1011579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method objectSwap = staticSwapMethod(Object.class, "objectValue");
1012579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Static.objectValue = "before";
1013579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("before", objectSwap.invoke(null, "after"));
1014579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("after", Static.objectValue);
1015579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1016579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method byteSwap = staticSwapMethod(byte.class, "byteValue");
1017579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Static.byteValue = 0x35;
1018579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals((byte) 0x35, byteSwap.invoke(null, (byte) 0x64));
1019579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals((byte) 0x64, Static.byteValue);
1020579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1021579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method charSwap = staticSwapMethod(char.class, "charValue");
1022579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Static.charValue = 'A';
1023579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals('A', charSwap.invoke(null, 'B'));
1024579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals('B', Static.charValue);
1025579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1026579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method shortSwap = staticSwapMethod(short.class, "shortValue");
1027579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Static.shortValue = (short) 0xabcd;
1028579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals((short) 0xabcd, shortSwap.invoke(null, (short) 0x1234));
1029579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals((short) 0x1234, Static.shortValue);
1030579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
1031579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1032579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static class Static {
1033579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public static int intValue;
1034579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public static long longValue;
1035579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public static float floatValue;
1036579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public static double doubleValue;
1037579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public static Object objectValue;
1038579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public static boolean booleanValue;
1039579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public static byte byteValue;
1040579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public static char charValue;
1041579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public static short shortValue;
1042579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
1043579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1044579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private <V> Method staticSwapMethod(Class<V> valueClass, String fieldName)
1045579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throws Exception {
1046579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
1047579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * public static int call(int newValue) {
1048579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   int oldValue = Static.intValue;
1049579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   Static.intValue = newValue;
1050579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   return oldValue;
1051579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * }
1052579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
1053579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        reset();
10540e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        TypeId<V> valueType = TypeId.get(valueClass);
10550e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        TypeId<Static> objectType = TypeId.get(Static.class);
1056579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        FieldId<Static, V> fieldId = objectType.getField(valueType, fieldName);
1057579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        MethodId<?, V> methodId = GENERATED.getMethod(valueType, "call", valueType);
1058ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson        Code code = dexMaker.declare(methodId, PUBLIC | STATIC);
1059579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Local<V> localNewValue = code.getParameter(0, valueType);
1060579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Local<V> localOldValue = code.newLocal(valueType);
1061579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.sget(fieldId, localOldValue);
1062579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.sput(fieldId, localNewValue);
1063579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.returnValue(localOldValue);
1064579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return getMethod();
1065579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
1066579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1067579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testTypeCast() throws Exception {
1068579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
1069579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * public static String call(Object o) {
1070579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   String s = (String) o;
1071579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * }
1072579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
10730e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        MethodId<?, String> methodId = GENERATED.getMethod(TypeId.STRING, "call", TypeId.OBJECT);
1074ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson        Code code = dexMaker.declare(methodId, PUBLIC | STATIC);
10750e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<Object> localObject = code.getParameter(0, TypeId.OBJECT);
10760e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<String> localString = code.newLocal(TypeId.STRING);
107797b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson        code.cast(localString, localObject);
1078579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.returnValue(localString);
1079579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1080579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method method = getMethod();
1081579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("s", method.invoke(null, "s"));
1082579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(null, method.invoke(null, (String) null));
1083579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        try {
1084579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            method.invoke(null, 5);
1085579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            fail();
1086579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (InvocationTargetException expected) {
1087579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            assertEquals(ClassCastException.class, expected.getCause().getClass());
1088579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
1089579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
1090579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1091579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testInstanceOf() throws Exception {
1092579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
1093579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * public static boolean call(Object o) {
1094579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   boolean result = o instanceof String;
1095579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   return result;
1096579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * }
1097579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
10980e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        MethodId<?, Boolean> methodId = GENERATED.getMethod(TypeId.BOOLEAN, "call", TypeId.OBJECT);
1099ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson        Code code = dexMaker.declare(methodId, PUBLIC | STATIC);
11000e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<Object> localObject = code.getParameter(0, TypeId.OBJECT);
11010e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<Boolean> localResult = code.newLocal(TypeId.BOOLEAN);
11020e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        code.instanceOfType(localResult, localObject, TypeId.STRING);
1103579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.returnValue(localResult);
1104579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1105579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method method = getMethod();
1106579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(true, method.invoke(null, "s"));
1107579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(false, method.invoke(null, (String) null));
1108579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(false, method.invoke(null, 5));
1109579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
1110579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1111579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
1112579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Tests that we can construct a for loop.
1113579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
1114579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testForLoop() throws Exception {
1115579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
1116579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * public static int call(int count) {
1117579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   int result = 1;
1118579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   for (int i = 0; i < count; i += 1) {
1119579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *     result = result * 2;
1120579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   }
1121579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   return result;
1122579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * }
1123579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
11240e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        MethodId<?, Integer> methodId = GENERATED.getMethod(TypeId.INT, "call", TypeId.INT);
1125ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson        Code code = dexMaker.declare(methodId, PUBLIC | STATIC);
11260e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<Integer> localCount = code.getParameter(0, TypeId.INT);
11270e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<Integer> localResult = code.newLocal(TypeId.INT);
11280e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<Integer> localI = code.newLocal(TypeId.INT);
11290e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<Integer> local1 = code.newLocal(TypeId.INT);
11300e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<Integer> local2 = code.newLocal(TypeId.INT);
1131579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.loadConstant(local1, 1);
1132579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.loadConstant(local2, 2);
1133579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.loadConstant(localResult, 1);
1134579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.loadConstant(localI, 0);
113523abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson        Label loopCondition = new Label();
113623abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson        Label loopBody = new Label();
113723abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson        Label afterLoop = new Label();
1138579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.mark(loopCondition);
11390e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        code.compare(Comparison.LT, loopBody, localI, localCount);
1140579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.jump(afterLoop);
1141579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.mark(loopBody);
1142579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.op(BinaryOp.MULTIPLY, localResult, localResult, local2);
1143579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.op(BinaryOp.ADD, localI, localI, local1);
1144579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.jump(loopCondition);
1145579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.mark(afterLoop);
1146579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.returnValue(localResult);
1147579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1148579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method pow2 = getMethod();
1149579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(1, pow2.invoke(null, 0));
1150579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(2, pow2.invoke(null, 1));
1151579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(4, pow2.invoke(null, 2));
1152579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(8, pow2.invoke(null, 3));
1153579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(16, pow2.invoke(null, 4));
1154579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
1155579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1156579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
1157579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Tests that we can construct a while loop.
1158579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
1159579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testWhileLoop() throws Exception {
1160579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
1161579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * public static int call(int max) {
1162579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   int result = 1;
1163579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   while (result < max) {
1164579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *     result = result * 2;
1165579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   }
1166579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   return result;
1167579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * }
1168579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
11690e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        MethodId<?, Integer> methodId = GENERATED.getMethod(TypeId.INT, "call", TypeId.INT);
1170ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson        Code code = dexMaker.declare(methodId, PUBLIC | STATIC);
11710e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<Integer> localMax = code.getParameter(0, TypeId.INT);
11720e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<Integer> localResult = code.newLocal(TypeId.INT);
11730e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<Integer> local2 = code.newLocal(TypeId.INT);
1174579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.loadConstant(localResult, 1);
1175579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.loadConstant(local2, 2);
117623abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson        Label loopCondition = new Label();
117723abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson        Label loopBody = new Label();
117823abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson        Label afterLoop = new Label();
1179579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.mark(loopCondition);
11800e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        code.compare(Comparison.LT, loopBody, localResult, localMax);
1181579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.jump(afterLoop);
1182579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.mark(loopBody);
1183579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.op(BinaryOp.MULTIPLY, localResult, localResult, local2);
1184579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.jump(loopCondition);
1185579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.mark(afterLoop);
1186579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.returnValue(localResult);
1187579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1188579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method ceilPow2 = getMethod();
1189579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(1, ceilPow2.invoke(null, 1));
1190579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(2, ceilPow2.invoke(null, 2));
1191579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(4, ceilPow2.invoke(null, 3));
1192579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(16, ceilPow2.invoke(null, 10));
1193579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(128, ceilPow2.invoke(null, 100));
1194579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(1024, ceilPow2.invoke(null, 1000));
1195579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
1196579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1197579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testIfElseBlock() throws Exception {
1198579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
1199579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * public static int call(int a, int b, int c) {
1200579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   if (a < b) {
1201579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *     if (a < c) {
1202579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *       return a;
1203579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *     } else {
1204579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *       return c;
1205579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *     }
1206579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   } else if (b < c) {
1207579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *     return b;
1208579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   } else {
1209579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *     return c;
1210579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   }
1211579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * }
1212579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
1213579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        MethodId<?, Integer> methodId = GENERATED.getMethod(
12140e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson                TypeId.INT, "call", TypeId.INT, TypeId.INT, TypeId.INT);
1215ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson        Code code = dexMaker.declare(methodId, PUBLIC | STATIC);
12160e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<Integer> localA = code.getParameter(0, TypeId.INT);
12170e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<Integer> localB = code.getParameter(1, TypeId.INT);
12180e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<Integer> localC = code.getParameter(2, TypeId.INT);
121923abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson        Label aLessThanB = new Label();
122023abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson        Label aLessThanC = new Label();
122123abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson        Label bLessThanC = new Label();
12220e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        code.compare(Comparison.LT, aLessThanB, localA, localB);
12230e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        code.compare(Comparison.LT, bLessThanC, localB, localC);
1224579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.returnValue(localC);
1225579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        // (a < b)
1226579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.mark(aLessThanB);
12270e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        code.compare(Comparison.LT, aLessThanC, localA, localC);
1228579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.returnValue(localC);
1229579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        // (a < c)
1230579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.mark(aLessThanC);
1231579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.returnValue(localA);
1232579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        // (b < c)
1233579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.mark(bLessThanC);
1234579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.returnValue(localB);
1235579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1236579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method min = getMethod();
1237579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(1, min.invoke(null, 1, 2, 3));
1238579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(1, min.invoke(null, 2, 3, 1));
1239579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(1, min.invoke(null, 2, 1, 3));
1240579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(1, min.invoke(null, 3, 2, 1));
1241579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
1242579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1243579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testRecursion() throws Exception {
1244579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
1245579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * public static int call(int a) {
1246579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   if (a < 2) {
1247579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *     return a;
1248579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   }
1249579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   a -= 1;
1250579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   int x = call(a)
1251579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   a -= 1;
1252579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   int y = call(a);
1253579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   int result = x + y;
1254579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   return result;
1255579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * }
1256579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
12570e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        MethodId<?, Integer> methodId = GENERATED.getMethod(TypeId.INT, "call", TypeId.INT);
1258ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson        Code code = dexMaker.declare(methodId, PUBLIC | STATIC);
12590e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<Integer> localA = code.getParameter(0, TypeId.INT);
12600e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<Integer> local1 = code.newLocal(TypeId.INT);
12610e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<Integer> local2 = code.newLocal(TypeId.INT);
12620e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<Integer> localX = code.newLocal(TypeId.INT);
12630e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<Integer> localY = code.newLocal(TypeId.INT);
12640e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<Integer> localResult = code.newLocal(TypeId.INT);
126523abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson        Label baseCase = new Label();
1266579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.loadConstant(local1, 1);
1267579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.loadConstant(local2, 2);
12680e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        code.compare(Comparison.LT, baseCase, localA, local2);
1269579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.op(BinaryOp.SUBTRACT, localA, localA, local1);
1270579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.invokeStatic(methodId, localX, localA);
1271579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.op(BinaryOp.SUBTRACT, localA, localA, local1);
1272579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.invokeStatic(methodId, localY, localA);
1273579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.op(BinaryOp.ADD, localResult, localX, localY);
1274579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.returnValue(localResult);
1275579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.mark(baseCase);
1276579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.returnValue(localA);
1277579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1278579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method fib = getMethod();
1279579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0, fib.invoke(null, 0));
1280579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(1, fib.invoke(null, 1));
1281579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(1, fib.invoke(null, 2));
1282579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(2, fib.invoke(null, 3));
1283579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(3, fib.invoke(null, 4));
1284579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(5, fib.invoke(null, 5));
1285579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(8, fib.invoke(null, 6));
1286579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
1287579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1288579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testCatchExceptions() throws Exception {
1289579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
1290579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * public static String call(int i) {
1291579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   try {
1292ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson         *     DexMakerTest.thrower(i);
1293579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *     return "NONE";
1294579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   } catch (IllegalArgumentException e) {
1295579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *     return "IAE";
1296579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   } catch (IllegalStateException e) {
1297579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *     return "ISE";
1298579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   } catch (RuntimeException e) {
1299579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *     return "RE";
1300579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   }
1301579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
13020e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        MethodId<?, String> methodId = GENERATED.getMethod(TypeId.STRING, "call", TypeId.INT);
1303ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson        Code code = dexMaker.declare(methodId, PUBLIC | STATIC);
13040e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<Integer> localI = code.getParameter(0, TypeId.INT);
13050e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<String> result = code.newLocal(TypeId.STRING);
130623abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson        Label catchIae = new Label();
130723abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson        Label catchIse = new Label();
130823abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson        Label catchRe = new Label();
1309579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
13100e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        code.addCatchClause(TypeId.get(IllegalArgumentException.class), catchIae);
13110e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        code.addCatchClause(TypeId.get(IllegalStateException.class), catchIse);
13120e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        code.addCatchClause(TypeId.get(RuntimeException.class), catchRe);
13130e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        MethodId<?, ?> thrower = TEST_TYPE.getMethod(TypeId.VOID, "thrower", TypeId.INT);
1314579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.invokeStatic(thrower, null, localI);
1315579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.loadConstant(result, "NONE");
1316579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.returnValue(result);
1317579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1318579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.mark(catchIae);
1319579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.loadConstant(result, "IAE");
1320579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.returnValue(result);
1321579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1322579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.mark(catchIse);
1323579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.loadConstant(result, "ISE");
1324579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.returnValue(result);
1325579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1326579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.mark(catchRe);
1327579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.loadConstant(result, "RE");
1328579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.returnValue(result);
1329579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1330579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method method = getMethod();
1331579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("NONE", method.invoke(null, 0));
1332579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("IAE", method.invoke(null, 1));
1333579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("ISE", method.invoke(null, 2));
1334579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("RE", method.invoke(null, 3));
1335579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        try {
1336579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            method.invoke(null, 4);
1337579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            fail();
1338579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (InvocationTargetException expected) {
1339579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            assertEquals(IOException.class, expected.getCause().getClass());
1340579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
1341579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
1342579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1343579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    @SuppressWarnings("unused") // called by generated code
1344579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static void thrower(int a) throws Exception {
1345579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        switch (a) {
1346579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        case 0:
1347579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return;
1348579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        case 1:
1349579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new IllegalArgumentException();
1350579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        case 2:
1351579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new IllegalStateException();
1352579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        case 3:
1353579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new UnsupportedOperationException();
1354579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        case 4:
1355579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new IOException();
1356579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        default:
1357579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new AssertionError();
1358579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
1359579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
1360579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1361579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testNestedCatchClauses() throws Exception {
1362579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
1363579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * public static String call(int a, int b, int c) {
1364579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   try {
1365ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson         *     DexMakerTest.thrower(a);
1366579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *     try {
1367ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson         *       DexMakerTest.thrower(b);
1368579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *     } catch (IllegalArgumentException) {
1369579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *       return "INNER";
1370579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *     }
1371ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson         *     DexMakerTest.thrower(c);
1372579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *     return "NONE";
1373579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   } catch (IllegalArgumentException e) {
1374579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *     return "OUTER";
1375579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   }
1376579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
1377579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        MethodId<?, String> methodId = GENERATED.getMethod(
13780e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson                TypeId.STRING, "call", TypeId.INT, TypeId.INT, TypeId.INT);
1379ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson        Code code = dexMaker.declare(methodId, PUBLIC | STATIC);
13800e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<Integer> localA = code.getParameter(0, TypeId.INT);
13810e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<Integer> localB = code.getParameter(1, TypeId.INT);
13820e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<Integer> localC = code.getParameter(2, TypeId.INT);
13830e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<String> localResult = code.newLocal(TypeId.STRING);
138423abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson        Label catchInner = new Label();
138523abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson        Label catchOuter = new Label();
1386579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
13870e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        TypeId<IllegalArgumentException> iaeType = TypeId.get(IllegalArgumentException.class);
1388579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.addCatchClause(iaeType, catchOuter);
1389579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
13900e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        MethodId<?, ?> thrower = TEST_TYPE.getMethod(TypeId.VOID, "thrower", TypeId.INT);
1391579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.invokeStatic(thrower, null, localA);
1392579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1393579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        // for the inner catch clause, we stash the old label and put it back afterwards.
1394579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Label previousLabel = code.removeCatchClause(iaeType);
1395579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.addCatchClause(iaeType, catchInner);
1396579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.invokeStatic(thrower, null, localB);
1397579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.removeCatchClause(iaeType);
1398579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.addCatchClause(iaeType, previousLabel);
1399579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.invokeStatic(thrower, null, localC);
1400579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.loadConstant(localResult, "NONE");
1401579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.returnValue(localResult);
1402579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1403579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.mark(catchInner);
1404579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.loadConstant(localResult, "INNER");
1405579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.returnValue(localResult);
1406579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1407579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.mark(catchOuter);
1408579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.loadConstant(localResult, "OUTER");
1409579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.returnValue(localResult);
1410579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1411579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method method = getMethod();
1412579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("OUTER", method.invoke(null, 1, 0, 0));
1413579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("INNER", method.invoke(null, 0, 1, 0));
1414579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("OUTER", method.invoke(null, 0, 0, 1));
1415579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("NONE", method.invoke(null, 0, 0, 0));
1416579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
1417579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1418579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testThrow() throws Exception {
1419579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
1420579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * public static void call() {
1421579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   throw new IllegalStateException();
1422579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * }
1423579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
14240e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        MethodId<?, Void> methodId = GENERATED.getMethod(TypeId.VOID, "call");
1425ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson        Code code = dexMaker.declare(methodId, PUBLIC | STATIC);
14260e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        TypeId<IllegalStateException> iseType = TypeId.get(IllegalStateException.class);
1427579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        MethodId<IllegalStateException, Void> iseConstructor = iseType.getConstructor();
1428579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Local<IllegalStateException> localIse = code.newLocal(iseType);
1429579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.newInstance(localIse, iseConstructor);
1430579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.throwValue(localIse);
1431579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1432579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        try {
1433579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            getMethod().invoke(null);
1434579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            fail();
1435579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (InvocationTargetException expected) {
1436579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            assertEquals(IllegalStateException.class, expected.getCause().getClass());
1437579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
1438579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
1439579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1440579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testUnusedParameters() throws Exception {
1441579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
1442579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * public static void call(int unused1, long unused2, long unused3) {}
1443579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
1444579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        MethodId<?, Void> methodId = GENERATED.getMethod(
14450e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson                TypeId.VOID, "call", TypeId.INT, TypeId.LONG, TypeId.LONG);
1446ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson        Code code = dexMaker.declare(methodId, PUBLIC | STATIC);
1447579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.returnVoid();
1448579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        getMethod().invoke(null, 1, 2, 3);
1449579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
1450579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1451579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testFloatingPointCompare() throws Exception {
14520e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Method floatG = floatingPointCompareMethod(TypeId.FLOAT, 1);
1453579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(-1, floatG.invoke(null, 1.0f, Float.POSITIVE_INFINITY));
1454579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(-1, floatG.invoke(null, 1.0f, 2.0f));
1455579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0, floatG.invoke(null, 1.0f, 1.0f));
1456579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(1, floatG.invoke(null, 2.0f, 1.0f));
1457579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(1, floatG.invoke(null, 1.0f, Float.NaN));
1458579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(1, floatG.invoke(null, Float.NaN, 1.0f));
1459579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(1, floatG.invoke(null, Float.NaN, Float.NaN));
1460579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(1, floatG.invoke(null, Float.NaN, Float.POSITIVE_INFINITY));
1461579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
14620e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Method floatL = floatingPointCompareMethod(TypeId.FLOAT, -1);
1463579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(-1, floatG.invoke(null, 1.0f, Float.POSITIVE_INFINITY));
1464579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(-1, floatL.invoke(null, 1.0f, 2.0f));
1465579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0, floatL.invoke(null, 1.0f, 1.0f));
1466579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(1, floatL.invoke(null, 2.0f, 1.0f));
1467579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(-1, floatL.invoke(null, 1.0f, Float.NaN));
1468579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(-1, floatL.invoke(null, Float.NaN, 1.0f));
1469579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(-1, floatL.invoke(null, Float.NaN, Float.NaN));
1470579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(-1, floatL.invoke(null, Float.NaN, Float.POSITIVE_INFINITY));
1471579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
14720e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Method doubleG = floatingPointCompareMethod(TypeId.DOUBLE, 1);
1473579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(-1, doubleG.invoke(null, 1.0, Double.POSITIVE_INFINITY));
1474579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(-1, doubleG.invoke(null, 1.0, 2.0));
1475579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0, doubleG.invoke(null, 1.0, 1.0));
1476579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(1, doubleG.invoke(null, 2.0, 1.0));
1477579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(1, doubleG.invoke(null, 1.0, Double.NaN));
1478579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(1, doubleG.invoke(null, Double.NaN, 1.0));
1479579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(1, doubleG.invoke(null, Double.NaN, Double.NaN));
1480579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(1, doubleG.invoke(null, Double.NaN, Double.POSITIVE_INFINITY));
1481579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
14820e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Method doubleL = floatingPointCompareMethod(TypeId.DOUBLE, -1);
1483579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(-1, doubleL.invoke(null, 1.0, Double.POSITIVE_INFINITY));
1484579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(-1, doubleL.invoke(null, 1.0, 2.0));
1485579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0, doubleL.invoke(null, 1.0, 1.0));
1486579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(1, doubleL.invoke(null, 2.0, 1.0));
1487579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(-1, doubleL.invoke(null, 1.0, Double.NaN));
1488579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(-1, doubleL.invoke(null, Double.NaN, 1.0));
1489579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(-1, doubleL.invoke(null, Double.NaN, Double.NaN));
1490579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(-1, doubleL.invoke(null, Double.NaN, Double.POSITIVE_INFINITY));
1491579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
1492579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1493579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private <T extends Number> Method floatingPointCompareMethod(
14940e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson            TypeId<T> valueType, int nanValue) throws Exception {
1495579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
1496579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * public static int call(float a, float b) {
1497579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *     int result = a <=> b;
1498579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *     return result;
1499579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * }
1500579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
1501579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        reset();
15020e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        MethodId<?, Integer> methodId = GENERATED.getMethod(
15030e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson                TypeId.INT, "call", valueType, valueType);
1504ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson        Code code = dexMaker.declare(methodId, PUBLIC | STATIC);
1505579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Local<T> localA = code.getParameter(0, valueType);
1506579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Local<T> localB = code.getParameter(1, valueType);
15070e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<Integer> localResult = code.newLocal(TypeId.INT);
1508d6c77efc0b187577dd7956070adfc7c335f65698Jesse Wilson        code.compareFloatingPoint(localResult, localA, localB, nanValue);
1509579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.returnValue(localResult);
1510579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return getMethod();
1511579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
1512579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1513579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testLongCompare() throws Exception {
1514579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
1515579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * public static int call(long a, long b) {
1516579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   int result = a <=> b;
1517579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   return result;
1518579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * }
1519579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
15200e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        MethodId<?, Integer> methodId = GENERATED.getMethod(TypeId.INT, "call", TypeId.LONG, TypeId.LONG);
1521ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson        Code code = dexMaker.declare(methodId, PUBLIC | STATIC);
15220e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<Long> localA = code.getParameter(0, TypeId.LONG);
15230e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<Long> localB = code.getParameter(1, TypeId.LONG);
15240e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<Integer> localResult = code.newLocal(TypeId.INT);
1525d6c77efc0b187577dd7956070adfc7c335f65698Jesse Wilson        code.compareLongs(localResult, localA, localB);
1526579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.returnValue(localResult);
1527579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1528579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method method = getMethod();
1529579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0, method.invoke(null, Long.MIN_VALUE, Long.MIN_VALUE));
1530579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(-1, method.invoke(null, Long.MIN_VALUE, 0));
1531579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(-1, method.invoke(null, Long.MIN_VALUE, Long.MAX_VALUE));
1532579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(1, method.invoke(null, 0, Long.MIN_VALUE));
1533579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0, method.invoke(null, 0, 0));
1534579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(-1, method.invoke(null, 0, Long.MAX_VALUE));
1535579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(1, method.invoke(null, Long.MAX_VALUE, Long.MIN_VALUE));
1536579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(1, method.invoke(null, Long.MAX_VALUE, 0));
1537579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0, method.invoke(null, Long.MAX_VALUE, Long.MAX_VALUE));
1538579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
1539579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1540579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testArrayLength() throws Exception {
1541579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method booleanArrayLength = arrayLengthMethod(BOOLEAN_ARRAY);
1542579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0, booleanArrayLength.invoke(null, new Object[] { new boolean[0] }));
1543579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(5, booleanArrayLength.invoke(null, new Object[] { new boolean[5] }));
1544579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1545579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method intArrayLength = arrayLengthMethod(INT_ARRAY);
1546579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0, intArrayLength.invoke(null, new Object[] { new int[0] }));
1547579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(5, intArrayLength.invoke(null, new Object[] { new int[5] }));
1548579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1549579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method longArrayLength = arrayLengthMethod(LONG_ARRAY);
1550242b6fb150cd9fc4e0b871b9595bc1bdd84cceabJesse Wilson        assertEquals(0, longArrayLength.invoke(null, new Object[] { new long[0] }));
1551579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(5, longArrayLength.invoke(null, new Object[] { new long[5] }));
1552579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1553579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method objectArrayLength = arrayLengthMethod(OBJECT_ARRAY);
1554579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0, objectArrayLength.invoke(null, new Object[] { new Object[0] }));
1555579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(5, objectArrayLength.invoke(null, new Object[] { new Object[5] }));
1556579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1557579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method long2dArrayLength = arrayLengthMethod(LONG_2D_ARRAY);
1558579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0, long2dArrayLength.invoke(null, new Object[] { new long[0][0] }));
1559579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(5, long2dArrayLength.invoke(null, new Object[] { new long[5][10] }));
1560579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
1561579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
15620e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson    private <T> Method arrayLengthMethod(TypeId<T> valueType) throws Exception {
1563579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
1564579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * public static int call(long[] array) {
1565579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   int result = array.length;
1566579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   return result;
1567579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * }
1568579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
1569579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        reset();
15700e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        MethodId<?, Integer> methodId = GENERATED.getMethod(TypeId.INT, "call", valueType);
1571ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson        Code code = dexMaker.declare(methodId, PUBLIC | STATIC);
1572579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Local<T> localArray = code.getParameter(0, valueType);
15730e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<Integer> localResult = code.newLocal(TypeId.INT);
15740e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        code.arrayLength(localResult, localArray);
1575579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.returnValue(localResult);
1576579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return getMethod();
1577579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
1578579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1579579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testNewArray() throws Exception {
1580579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method newBooleanArray = newArrayMethod(BOOLEAN_ARRAY);
1581579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("[]", Arrays.toString((boolean[]) newBooleanArray.invoke(null, 0)));
1582579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("[false, false, false]",
1583579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                Arrays.toString((boolean[]) newBooleanArray.invoke(null, 3)));
1584579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1585579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method newIntArray = newArrayMethod(INT_ARRAY);
1586579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("[]", Arrays.toString((int[]) newIntArray.invoke(null, 0)));
1587579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("[0, 0, 0]", Arrays.toString((int[]) newIntArray.invoke(null, 3)));
1588579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1589579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method newLongArray = newArrayMethod(LONG_ARRAY);
1590579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("[]", Arrays.toString((long[]) newLongArray.invoke(null, 0)));
1591579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("[0, 0, 0]", Arrays.toString((long[]) newLongArray.invoke(null, 3)));
1592579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1593579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method newObjectArray = newArrayMethod(OBJECT_ARRAY);
1594579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("[]", Arrays.toString((Object[]) newObjectArray.invoke(null, 0)));
1595579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("[null, null, null]",
1596579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                Arrays.toString((Object[]) newObjectArray.invoke(null, 3)));
1597579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1598579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method new2dLongArray = newArrayMethod(LONG_2D_ARRAY);
1599579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("[]", Arrays.deepToString((long[][]) new2dLongArray.invoke(null, 0)));
1600579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("[null, null, null]",
1601579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                Arrays.deepToString((long[][]) new2dLongArray.invoke(null, 3)));
1602579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
1603579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
16040e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson    private <T> Method newArrayMethod(TypeId<T> valueType) throws Exception {
1605579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
1606579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * public static long[] call(int length) {
1607579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   long[] result = new long[length];
1608579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   return result;
1609579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * }
1610579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
1611579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        reset();
16120e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        MethodId<?, T> methodId = GENERATED.getMethod(valueType, "call", TypeId.INT);
1613ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson        Code code = dexMaker.declare(methodId, PUBLIC | STATIC);
16140e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<Integer> localLength = code.getParameter(0, TypeId.INT);
1615579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Local<T> localResult = code.newLocal(valueType);
16160e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        code.newArray(localResult, localLength);
1617579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.returnValue(localResult);
1618579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return getMethod();
1619579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
1620579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1621579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void testReadAndWriteArray() throws Exception {
16220e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Method swapBooleanArray = arraySwapMethod(BOOLEAN_ARRAY, TypeId.BOOLEAN);
1623579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        boolean[] booleans = new boolean[3];
1624579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(false, swapBooleanArray.invoke(null, booleans, 1, true));
1625579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("[false, true, false]", Arrays.toString(booleans));
1626579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
16270e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Method swapIntArray = arraySwapMethod(INT_ARRAY, TypeId.INT);
1628579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int[] ints = new int[3];
1629579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0, swapIntArray.invoke(null, ints, 1, 5));
1630579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("[0, 5, 0]", Arrays.toString(ints));
1631579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
16320e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Method swapLongArray = arraySwapMethod(LONG_ARRAY, TypeId.LONG);
1633579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        long[] longs = new long[3];
1634579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(0L, swapLongArray.invoke(null, longs, 1, 6L));
1635579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("[0, 6, 0]", Arrays.toString(longs));
1636579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
16370e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Method swapObjectArray = arraySwapMethod(OBJECT_ARRAY, TypeId.OBJECT);
1638579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Object[] objects = new Object[3];
1639579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(null, swapObjectArray.invoke(null, objects, 1, "X"));
1640579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("[null, X, null]", Arrays.toString(objects));
1641579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1642579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Method swapLong2dArray = arraySwapMethod(LONG_2D_ARRAY, LONG_ARRAY);
1643579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        long[][] longs2d = new long[3][];
1644579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals(null, swapLong2dArray.invoke(null, longs2d, 1, new long[] { 7 }));
1645579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        assertEquals("[null, [7], null]", Arrays.deepToString(longs2d));
1646579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
1647579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
16480e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson    private <A, T> Method arraySwapMethod(TypeId<A> arrayType, TypeId<T> singleType)
1649579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throws Exception {
1650579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
1651579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * public static long swap(long[] array, int index, long newValue) {
1652579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   long result = array[index];
1653579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   array[index] = newValue;
1654579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *   return result;
1655579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * }
1656579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
1657579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        reset();
1658579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        MethodId<?, T> methodId = GENERATED.getMethod(
16590e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson                singleType, "call", arrayType, TypeId.INT, singleType);
1660ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson        Code code = dexMaker.declare(methodId, PUBLIC | STATIC);
1661579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Local<A> localArray = code.getParameter(0, arrayType);
16620e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        Local<Integer> localIndex = code.getParameter(1, TypeId.INT);
1663579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Local<T> localNewValue = code.getParameter(2, singleType);
1664579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Local<T> localResult = code.newLocal(singleType);
16650e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        code.aget(localResult, localArray, localIndex);
1666579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.aput(localArray, localIndex, localNewValue);
1667579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.returnValue(localResult);
1668579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return getMethod();
1669579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
1670579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
16715624228626d7cdf206de25a6981ba8107be61057Jesse Wilson    public void testSynchronizedFlagImpactsDeclarationOnly() throws Exception {
16725624228626d7cdf206de25a6981ba8107be61057Jesse Wilson        /*
16735624228626d7cdf206de25a6981ba8107be61057Jesse Wilson         * public synchronized void call() {
16745624228626d7cdf206de25a6981ba8107be61057Jesse Wilson         *   wait(100L);
16755624228626d7cdf206de25a6981ba8107be61057Jesse Wilson         * }
16765624228626d7cdf206de25a6981ba8107be61057Jesse Wilson         */
16775624228626d7cdf206de25a6981ba8107be61057Jesse Wilson        MethodId<?, Void> methodId = GENERATED.getMethod(TypeId.VOID, "call");
16785624228626d7cdf206de25a6981ba8107be61057Jesse Wilson        MethodId<Object, Void> wait = TypeId.OBJECT.getMethod(TypeId.VOID, "wait", TypeId.LONG);
16795624228626d7cdf206de25a6981ba8107be61057Jesse Wilson        Code code = dexMaker.declare(methodId, PUBLIC | SYNCHRONIZED);
16805624228626d7cdf206de25a6981ba8107be61057Jesse Wilson        Local<?> thisLocal = code.getThis(GENERATED);
16815624228626d7cdf206de25a6981ba8107be61057Jesse Wilson        Local<Long> timeout = code.newLocal(TypeId.LONG);
16825624228626d7cdf206de25a6981ba8107be61057Jesse Wilson        code.loadConstant(timeout, 100L);
16835624228626d7cdf206de25a6981ba8107be61057Jesse Wilson        code.invokeVirtual(wait, null, thisLocal, timeout);
16845624228626d7cdf206de25a6981ba8107be61057Jesse Wilson        code.returnVoid();
16855624228626d7cdf206de25a6981ba8107be61057Jesse Wilson
16865624228626d7cdf206de25a6981ba8107be61057Jesse Wilson        addDefaultConstructor();
16875624228626d7cdf206de25a6981ba8107be61057Jesse Wilson
16885624228626d7cdf206de25a6981ba8107be61057Jesse Wilson        Class<?> generatedClass = generateAndLoad();
16895624228626d7cdf206de25a6981ba8107be61057Jesse Wilson        Object instance = generatedClass.newInstance();
16905624228626d7cdf206de25a6981ba8107be61057Jesse Wilson        Method method = generatedClass.getMethod("call");
16915624228626d7cdf206de25a6981ba8107be61057Jesse Wilson        assertTrue(Modifier.isSynchronized(method.getModifiers()));
16925624228626d7cdf206de25a6981ba8107be61057Jesse Wilson        try {
16935624228626d7cdf206de25a6981ba8107be61057Jesse Wilson            method.invoke(instance);
16945624228626d7cdf206de25a6981ba8107be61057Jesse Wilson            fail();
16955624228626d7cdf206de25a6981ba8107be61057Jesse Wilson        } catch (InvocationTargetException expected) {
16965624228626d7cdf206de25a6981ba8107be61057Jesse Wilson            assertTrue(expected.getCause() instanceof IllegalMonitorStateException);
16975624228626d7cdf206de25a6981ba8107be61057Jesse Wilson        }
16985624228626d7cdf206de25a6981ba8107be61057Jesse Wilson    }
16995624228626d7cdf206de25a6981ba8107be61057Jesse Wilson
17005624228626d7cdf206de25a6981ba8107be61057Jesse Wilson    public void testMonitorEnterMonitorExit() throws Exception {
17015624228626d7cdf206de25a6981ba8107be61057Jesse Wilson        /*
17025624228626d7cdf206de25a6981ba8107be61057Jesse Wilson         * public synchronized void call() {
17035624228626d7cdf206de25a6981ba8107be61057Jesse Wilson         *   synchronized (this) {
17045624228626d7cdf206de25a6981ba8107be61057Jesse Wilson         *     wait(100L);
17055624228626d7cdf206de25a6981ba8107be61057Jesse Wilson         *   }
17065624228626d7cdf206de25a6981ba8107be61057Jesse Wilson         * }
17075624228626d7cdf206de25a6981ba8107be61057Jesse Wilson         */
17085624228626d7cdf206de25a6981ba8107be61057Jesse Wilson        MethodId<?, Void> methodId = GENERATED.getMethod(TypeId.VOID, "call");
17095624228626d7cdf206de25a6981ba8107be61057Jesse Wilson        MethodId<Object, Void> wait = TypeId.OBJECT.getMethod(TypeId.VOID, "wait", TypeId.LONG);
17105624228626d7cdf206de25a6981ba8107be61057Jesse Wilson        Code code = dexMaker.declare(methodId, PUBLIC);
17115624228626d7cdf206de25a6981ba8107be61057Jesse Wilson        Local<?> thisLocal = code.getThis(GENERATED);
17125624228626d7cdf206de25a6981ba8107be61057Jesse Wilson        Local<Long> timeout = code.newLocal(TypeId.LONG);
17135624228626d7cdf206de25a6981ba8107be61057Jesse Wilson        code.monitorEnter(thisLocal);
17145624228626d7cdf206de25a6981ba8107be61057Jesse Wilson        code.loadConstant(timeout, 100L);
17155624228626d7cdf206de25a6981ba8107be61057Jesse Wilson        code.invokeVirtual(wait, null, thisLocal, timeout);
17165624228626d7cdf206de25a6981ba8107be61057Jesse Wilson        code.monitorExit(thisLocal);
17175624228626d7cdf206de25a6981ba8107be61057Jesse Wilson        code.returnVoid();
17185624228626d7cdf206de25a6981ba8107be61057Jesse Wilson
17195624228626d7cdf206de25a6981ba8107be61057Jesse Wilson        addDefaultConstructor();
17205624228626d7cdf206de25a6981ba8107be61057Jesse Wilson
17215624228626d7cdf206de25a6981ba8107be61057Jesse Wilson        Class<?> generatedClass = generateAndLoad();
17225624228626d7cdf206de25a6981ba8107be61057Jesse Wilson        Object instance = generatedClass.newInstance();
17235624228626d7cdf206de25a6981ba8107be61057Jesse Wilson        Method method = generatedClass.getMethod("call");
17245624228626d7cdf206de25a6981ba8107be61057Jesse Wilson        assertFalse(Modifier.isSynchronized(method.getModifiers()));
17255624228626d7cdf206de25a6981ba8107be61057Jesse Wilson        method.invoke(instance); // will take 100ms
17265624228626d7cdf206de25a6981ba8107be61057Jesse Wilson    }
17275624228626d7cdf206de25a6981ba8107be61057Jesse Wilson
17284838105a39ae6c608c2a0e242ead249d8683a5d0Jesse Wilson    public void testMoveInt() throws Exception {
17294838105a39ae6c608c2a0e242ead249d8683a5d0Jesse Wilson        /*
17304838105a39ae6c608c2a0e242ead249d8683a5d0Jesse Wilson         * public static int call(int a) {
17314838105a39ae6c608c2a0e242ead249d8683a5d0Jesse Wilson         *   int b = a;
17324838105a39ae6c608c2a0e242ead249d8683a5d0Jesse Wilson         *   int c = a + b;
17334838105a39ae6c608c2a0e242ead249d8683a5d0Jesse Wilson         *   return c;
17344838105a39ae6c608c2a0e242ead249d8683a5d0Jesse Wilson         * }
17354838105a39ae6c608c2a0e242ead249d8683a5d0Jesse Wilson         */
17364838105a39ae6c608c2a0e242ead249d8683a5d0Jesse Wilson        MethodId<?, Integer> methodId = GENERATED.getMethod(TypeId.INT, "call", TypeId.INT);
17374838105a39ae6c608c2a0e242ead249d8683a5d0Jesse Wilson        Code code = dexMaker.declare(methodId, PUBLIC | STATIC);
17384838105a39ae6c608c2a0e242ead249d8683a5d0Jesse Wilson        Local<Integer> a = code.getParameter(0, TypeId.INT);
17394838105a39ae6c608c2a0e242ead249d8683a5d0Jesse Wilson        Local<Integer> b = code.newLocal(TypeId.INT);
17404838105a39ae6c608c2a0e242ead249d8683a5d0Jesse Wilson        Local<Integer> c = code.newLocal(TypeId.INT);
17414838105a39ae6c608c2a0e242ead249d8683a5d0Jesse Wilson        code.move(b, a);
17424838105a39ae6c608c2a0e242ead249d8683a5d0Jesse Wilson        code.op(BinaryOp.ADD, c, a, b);
17434838105a39ae6c608c2a0e242ead249d8683a5d0Jesse Wilson        code.returnValue(c);
17444838105a39ae6c608c2a0e242ead249d8683a5d0Jesse Wilson
17454838105a39ae6c608c2a0e242ead249d8683a5d0Jesse Wilson        assertEquals(6, getMethod().invoke(null, 3));
17464838105a39ae6c608c2a0e242ead249d8683a5d0Jesse Wilson    }
17474838105a39ae6c608c2a0e242ead249d8683a5d0Jesse Wilson
1748c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson    public void testPrivateClassesAreUnsupported() {
1749c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson        try {
1750c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson            dexMaker.declare(TypeId.get("LPrivateClass;"), "PrivateClass.generated", PRIVATE,
1751c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson                    TypeId.OBJECT);
1752c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson            fail();
1753c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson        } catch (IllegalArgumentException expected) {
1754c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson        }
1755c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson    }
1756c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson
1757c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson    public void testAbstractMethodsAreUnsupported() {
1758c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson        MethodId<?, Void> methodId = GENERATED.getMethod(TypeId.VOID, "call");
1759c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson        try {
1760c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson            dexMaker.declare(methodId, ABSTRACT);
1761c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson            fail();
1762c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson        } catch (IllegalArgumentException expected) {
1763c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson        }
1764c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson    }
1765c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson
1766c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson    public void testNativeMethodsAreUnsupported() {
1767c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson        MethodId<?, Void> methodId = GENERATED.getMethod(TypeId.VOID, "call");
1768c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson        try {
1769c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson            dexMaker.declare(methodId, NATIVE);
1770c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson            fail();
1771c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson        } catch (IllegalArgumentException expected) {
1772c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson        }
1773c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson    }
1774c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson
1775c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson    public void testSynchronizedFieldsAreUnsupported() {
1776c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson        try {
1777c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson            FieldId<?, ?> fieldId = GENERATED.getField(TypeId.OBJECT, "synchronizedField");
1778c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson            dexMaker.declare(fieldId, SYNCHRONIZED, null);
1779c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson            fail();
1780c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson        } catch (IllegalArgumentException expected) {
1781c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson        }
1782c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson    }
1783c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson
1784c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson    public void testInitialValueWithNonStaticField() {
1785c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson        try {
1786c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson            FieldId<?, ?> fieldId = GENERATED.getField(TypeId.OBJECT, "nonStaticField");
1787c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson            dexMaker.declare(fieldId, 0, 1);
1788c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson            fail();
1789c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson        } catch (IllegalArgumentException expected) {
1790c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson        }
1791c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson    }
1792c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson
179397b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson    // TODO: cast primitive to non-primitive
179497b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson    // TODO: cast non-primitive to primitive
179597b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson    // TODO: cast byte to integer
179697b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson    // TODO: cast byte to long
179797b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson    // TODO: cast long to byte
1798579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    // TODO: fail if a label is unreachable (never navigated to)
1799579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    // TODO: more strict type parameters: Integer on methods
1800579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    // TODO: don't generate multiple times (?)
180197b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson    // TODO: test array types
180297b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson    // TODO: test generating an interface
180323abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson    // TODO: declare native method or abstract method
1804d6c77efc0b187577dd7956070adfc7c335f65698Jesse Wilson    // TODO: get a thrown exception 'e' into a local
1805d6c77efc0b187577dd7956070adfc7c335f65698Jesse Wilson    // TODO: move a primitive or reference
1806d6c77efc0b187577dd7956070adfc7c335f65698Jesse Wilson
1807579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private void addDefaultConstructor() {
1808c0271e9981ddd85a13ed88defd0b5b1a5ccc6f46Jesse Wilson        Code code = dexMaker.declare(GENERATED.getConstructor(), PUBLIC);
1809579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Local<?> thisRef = code.getThis(GENERATED);
18100e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        code.invokeDirect(TypeId.OBJECT.getConstructor(), null, thisRef);
1811579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        code.returnVoid();
1812579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
1813579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
1814054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    public void testCaching_Methods() throws Exception {
1815054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        int origSize = getDataDirectory().listFiles().length;
1816054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        final String defaultMethodName = "call";
1817054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1818054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        dexMaker = new DexMaker();
1819054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        dexMaker.declare(GENERATED, "Generated.java", PUBLIC, TypeId.OBJECT);
1820054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        addMethodToDexMakerGenerator(TypeId.INT, defaultMethodName, TypeId.INT);
1821054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        generateAndLoad();
1822054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        // DexMaker writes two files to disk at a time: Generated_XXXX.jar and Generated_XXXX.dex.
1823054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals(origSize + 2, getDataDirectory().listFiles().length);
1824054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1825054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        long lastModified  = getJarFiles()[0].lastModified();
1826054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1827054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        // Create new dexmaker generator with same method signature.
1828054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        dexMaker = new DexMaker();
1829054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        dexMaker.declare(GENERATED, "Generated.java", PUBLIC, TypeId.OBJECT);
1830054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        addMethodToDexMakerGenerator(TypeId.INT, defaultMethodName, TypeId.INT);
1831054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        generateAndLoad();
1832054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals(origSize + 2, getDataDirectory().listFiles().length);
1833054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals(lastModified, getJarFiles()[0].lastModified());
1834054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1835054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        // Create new dexmaker generators with different params.
1836054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        dexMaker = new DexMaker();
1837054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        dexMaker.declare(GENERATED, "Generated.java", PUBLIC, TypeId.OBJECT);
1838054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        addMethodToDexMakerGenerator(TypeId.INT, defaultMethodName, TypeId.DOUBLE);
1839054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        generateAndLoad();
1840054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals(origSize + 4, getDataDirectory().listFiles().length);
1841054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1842054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        dexMaker = new DexMaker();
1843054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        dexMaker.declare(GENERATED, "Generated.java", PUBLIC, TypeId.OBJECT);
1844054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        addMethodToDexMakerGenerator(TypeId.INT, defaultMethodName, TypeId.INT, TypeId.DOUBLE);
1845054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        generateAndLoad();
1846054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals(origSize + 6, getDataDirectory().listFiles().length);
1847054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1848054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        // Create new dexmaker generator with different return types.
1849054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        dexMaker = new DexMaker();
1850054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        dexMaker.declare(GENERATED, "Generated.java", PUBLIC, TypeId.OBJECT);
1851054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        addMethodToDexMakerGenerator(TypeId.DOUBLE, defaultMethodName, TypeId.INT);
1852054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        generateAndLoad();
1853054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals(origSize + 8, getDataDirectory().listFiles().length);
1854054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1855054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        // Create new dexmaker generators with multiple methods.
1856054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        dexMaker = new DexMaker();
1857054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        dexMaker.declare(GENERATED, "Generated.java", PUBLIC, TypeId.OBJECT);
1858054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        addMethodToDexMakerGenerator(TypeId.INT, defaultMethodName, TypeId.INT);
1859054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        addMethodToDexMakerGenerator(TypeId.INT, defaultMethodName, TypeId.INT, TypeId.BOOLEAN); // new method
1860054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        generateAndLoad();
1861054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals(origSize + 10, getDataDirectory().listFiles().length);
1862054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1863054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        dexMaker = new DexMaker();
1864054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        dexMaker.declare(GENERATED, "Generated.java", PUBLIC, TypeId.OBJECT);
1865054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        addMethodToDexMakerGenerator(TypeId.INT, defaultMethodName, TypeId.INT, TypeId.BOOLEAN);
1866054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        addMethodToDexMakerGenerator(TypeId.INT, defaultMethodName, TypeId.INT);
1867054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        generateAndLoad();
1868054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals(origSize + 10, getDataDirectory().listFiles().length); // should already be cached.
1869054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1870054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        dexMaker = new DexMaker();
1871054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        dexMaker.declare(GENERATED, "Generated.java", PUBLIC, TypeId.OBJECT);
1872054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        addMethodToDexMakerGenerator(TypeId.INT, defaultMethodName, TypeId.INT);
1873054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        addMethodToDexMakerGenerator(TypeId.INT, defaultMethodName, TypeId.INT, TypeId.INT, TypeId.BOOLEAN); // new method
1874054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        generateAndLoad();
1875054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals(origSize + 12, getDataDirectory().listFiles().length);
1876054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1877054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        dexMaker = new DexMaker();
1878054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        dexMaker.declare(GENERATED, "Generated.java", PUBLIC, TypeId.OBJECT);
1879054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        addMethodToDexMakerGenerator(TypeId.INT, defaultMethodName, TypeId.INT);
1880054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        addMethodToDexMakerGenerator(TypeId.INT, defaultMethodName, TypeId.INT, TypeId.INT); // new method
1881054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        generateAndLoad();
1882054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals(origSize + 14, getDataDirectory().listFiles().length);
1883054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1884054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        dexMaker = new DexMaker();
1885054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        dexMaker.declare(GENERATED, "Generated.java", PUBLIC, TypeId.OBJECT);
1886054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        addMethodToDexMakerGenerator(TypeId.INT, "differentName", TypeId.INT); // new method
1887054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        addMethodToDexMakerGenerator(TypeId.INT, defaultMethodName, TypeId.INT, TypeId.BOOLEAN);
1888054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        generateAndLoad();
1889054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals(origSize + 16, getDataDirectory().listFiles().length);
1890054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
1891054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1892054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    public static class BlankClassA {
1893054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1894054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
1895054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1896054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    public static class BlankClassB {
1897054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1898054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
1899054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1900054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    public void testCaching_DifferentParentClasses() throws Exception {
1901054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        int origSize = getDataDirectory().listFiles().length;
1902054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        final String defaultMethodName = "call";
1903054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1904054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        // Create new dexmaker generator with BlankClassA as supertype.
1905054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        dexMaker = new DexMaker();
1906054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        dexMaker.declare(GENERATED, "Generated.java", PUBLIC, TypeId.get(BlankClassA.class));
1907054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        addMethodToDexMakerGenerator(TypeId.INT, defaultMethodName, TypeId.INT);
1908054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        generateAndLoad();
1909054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        // DexMaker writes two files to disk at a time: Generated_XXXX.jar and Generated_XXXX.dex.
1910054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals(origSize + 2, getDataDirectory().listFiles().length);
1911054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1912054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        // Create new dexmaker generator with BlankClassB as supertype.
1913054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        dexMaker = new DexMaker();
1914054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        dexMaker.declare(GENERATED, "Generated.java", PUBLIC, TypeId.get(BlankClassB.class));
1915054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        addMethodToDexMakerGenerator(TypeId.INT, defaultMethodName, TypeId.INT);
1916054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        generateAndLoad();
1917054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals(origSize + 4, getDataDirectory().listFiles().length);
1918054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1919054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
1920054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1921054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    private void addMethodToDexMakerGenerator(TypeId<?> typeId, String methodName, TypeId<?>... params) throws Exception {
1922054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        MethodId<?, ?> methodId = GENERATED.getMethod(typeId, methodName, params);
1923054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        Code code = dexMaker.declare(methodId, PUBLIC | STATIC);
1924054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        TypeId<IllegalStateException> iseType = TypeId.get(IllegalStateException.class);
1925054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        Local<IllegalStateException> localIse = code.newLocal(iseType);
1926054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        if (params.length > 0) {
1927054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            if (params[0] == typeId) {
1928054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef                Local<?> localResult = code.getParameter(0, TypeId.INT);
1929054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef                code.returnValue(localResult);
1930054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            } else {
1931054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef                code.throwValue(localIse);
1932054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            }
1933054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        } else {
1934054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            code.throwValue(localIse);
1935054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        }
1936054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
1937054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1938054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    public void testCaching_Constructors() throws Exception {
1939054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        int origSize = getDataDirectory().listFiles().length;
1940054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1941054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        // Create new dexmaker generator with Generated(int) constructor.
1942054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        dexMaker = new DexMaker();
1943054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        dexMaker.declare(GENERATED, "Generated.java", PUBLIC, TypeId.OBJECT);
1944054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        addConstructorToDexMakerGenerator(TypeId.INT);
1945054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        generateAndLoad();
1946054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        // DexMaker writes two files to disk at a time: Generated_XXXX.jar and Generated_XXXX.dex.
1947054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals(origSize + 2, getDataDirectory().listFiles().length);
1948054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1949054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        long lastModified  = getJarFiles()[0].lastModified();
1950054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1951054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        dexMaker = new DexMaker();
1952054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        dexMaker.declare(GENERATED, "Generated.java", PUBLIC, TypeId.OBJECT);
1953054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        addConstructorToDexMakerGenerator(TypeId.INT);
1954054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        generateAndLoad();
1955054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals(origSize + 2, getDataDirectory().listFiles().length);
1956054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals(lastModified, getJarFiles()[0].lastModified());
1957054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1958054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        // Create new dexmaker generator with Generated(boolean) constructor.
1959054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        dexMaker = new DexMaker();
1960054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        dexMaker.declare(GENERATED, "Generated.java", PUBLIC, TypeId.OBJECT);
1961054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        addConstructorToDexMakerGenerator(TypeId.BOOLEAN);
1962054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        generateAndLoad();
1963054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals(origSize + 4, getDataDirectory().listFiles().length);
1964054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1965054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        // Create new dexmaker generator with multiple constructors.
1966054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        dexMaker = new DexMaker();
1967054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        dexMaker.declare(GENERATED, "Generated.java", PUBLIC, TypeId.OBJECT);
1968054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        addConstructorToDexMakerGenerator(TypeId.INT);
1969054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        addConstructorToDexMakerGenerator(TypeId.BOOLEAN);
1970054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        generateAndLoad();
1971054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals(origSize + 6, getDataDirectory().listFiles().length);
1972054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1973054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        // Ensure that order of constructors does not affect caching decision.
1974054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        dexMaker = new DexMaker();
1975054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        dexMaker.declare(GENERATED, "Generated.java", PUBLIC, TypeId.OBJECT);
1976054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        addConstructorToDexMakerGenerator(TypeId.BOOLEAN);
1977054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        addConstructorToDexMakerGenerator(TypeId.INT);
1978054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        generateAndLoad();
1979054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        assertEquals(origSize + 6, getDataDirectory().listFiles().length);
1980054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
1981054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1982054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    private void addConstructorToDexMakerGenerator(TypeId<?>... params) throws Exception {
1983054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        MethodId<?, Void> constructor = GENERATED.getConstructor(params);
1984054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        Code code = dexMaker.declare(constructor, PUBLIC);
1985054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        code.returnVoid();
1986054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
1987054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1988054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    private File[] getJarFiles() {
1989054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        return getDataDirectory().listFiles(new FilenameFilter() {
1990054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            public boolean accept(File dir, String name) {
1991054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef                return name.endsWith(".jar");
1992054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef            }
1993054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef        });
1994054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef    }
1995054604d4c95cb530bea955718d79dbe3dc0962cfAndrew Yousef
1996579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
1997579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Returns the generated method.
1998579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
1999579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private Method getMethod() throws Exception {
2000b3b96215f3dcbacb3f0d86780ac635cfc14ae9cfJesse Wilson        Class<?> generated = generateAndLoad();
2001579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (Method method : generated.getMethods()) {
2002579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (method.getName().equals("call")) {
2003579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                return method;
2004579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
2005579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
2006579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        throw new IllegalStateException("no call() method");
2007579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
2008579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
20097ff2c5291c7e0840ef62842372df0c2ecd5979f4Andrew Yousef    public static File getDataDirectory() {
20107ff2c5291c7e0840ef62842372df0c2ecd5979f4Andrew Yousef        String envVariable = "ANDROID_DATA";
20117ff2c5291c7e0840ef62842372df0c2ecd5979f4Andrew Yousef        String defaultLoc = "/data";
20127ff2c5291c7e0840ef62842372df0c2ecd5979f4Andrew Yousef        String path = System.getenv(envVariable);
20137ff2c5291c7e0840ef62842372df0c2ecd5979f4Andrew Yousef        return path == null ? new File(defaultLoc) : new File(path);
2014579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
2015579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
2016b3b96215f3dcbacb3f0d86780ac635cfc14ae9cfJesse Wilson    private Class<?> generateAndLoad() throws Exception {
2017ff314e1f06b974be78de3356a71072dbf0a450cdJesse Wilson        return dexMaker.generateAndLoad(getClass().getClassLoader(), getDataDirectory())
2018ff314e1f06b974be78de3356a71072dbf0a450cdJesse Wilson                .loadClass("Generated");
2019579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
2020579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson}
2021