1579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson/*
2579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Copyright (C) 2011 The Android Open Source Project
3579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
4579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Licensed under the Apache License, Version 2.0 (the "License");
5579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * you may not use this file except in compliance with the License.
6579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * You may obtain a copy of the License at
7579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
8579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *      http://www.apache.org/licenses/LICENSE-2.0
9579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
10579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Unless required by applicable law or agreed to in writing, software
11579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS,
12579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * See the License for the specific language governing permissions and
14579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * limitations under the License.
15579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */
16579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
17b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffinpackage com.android.dx;
18579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
19579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.code.BasicBlockList;
20579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.code.Insn;
21579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.code.PlainCstInsn;
22579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.code.PlainInsn;
23579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.code.RegisterSpecList;
24579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.code.Rop;
25579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.code.Rops;
26579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.code.SourcePosition;
27579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.code.ThrowingCstInsn;
28579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.code.ThrowingInsn;
29579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.cst.CstInteger;
30579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.type.StdTypeList;
31b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin
32579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.util.ArrayList;
33579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.util.Collections;
34579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.util.Iterator;
35579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.util.List;
36579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
37b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffinimport static com.android.dx.rop.code.Rop.BRANCH_GOTO;
38b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffinimport static com.android.dx.rop.code.Rop.BRANCH_NONE;
39b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffinimport static com.android.dx.rop.code.Rop.BRANCH_RETURN;
40b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffinimport static com.android.dx.rop.type.Type.BT_BYTE;
41b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffinimport static com.android.dx.rop.type.Type.BT_CHAR;
42b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffinimport static com.android.dx.rop.type.Type.BT_INT;
43b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffinimport static com.android.dx.rop.type.Type.BT_SHORT;
44b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin
45579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson/**
46579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Builds a sequence of instructions.
47d6c77efc0b187577dd7956070adfc7c335f65698Jesse Wilson *
48d6c77efc0b187577dd7956070adfc7c335f65698Jesse Wilson * <h3>Locals</h3>
49d6c77efc0b187577dd7956070adfc7c335f65698Jesse Wilson * All data manipulation takes place in local variables. Each parameter gets its
503e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * own local by default; access these using {@link #getParameter
513e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * getParameter()}. Non-static methods and constructors also have a {@code this}
523e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * parameter; it's available as {@link #getThis getThis()}. Allocate a new local
533e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * variable using {@link #newLocal newLocal()}, and assign a default value to it
543e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * with {@link #loadConstant loadConstant()}. Copy a value from one local to
553e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * another with {@link #move move()}.
563e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson *
573e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * <p>Every local variable has a fixed type. This is either a primitive type (of
583e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * any size) or a reference type.  This class emits instructions appropriate to
593e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * the types they operate on. Not all operations are local on all types;
603e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * attempting to emit such an operation will fail with an unchecked exception.
61d6c77efc0b187577dd7956070adfc7c335f65698Jesse Wilson *
62d6c77efc0b187577dd7956070adfc7c335f65698Jesse Wilson * <h3>Math and Bit Operations</h3>
63d6c77efc0b187577dd7956070adfc7c335f65698Jesse Wilson * Transform a single value into another related value using {@link
643e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * #op(UnaryOp,Local,Local) op(UnaryOp, Local, Local)}. Transform two values
653e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * into a third value using {@link #op(BinaryOp,Local,Local,Local) op(BinaryOp,
663e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * Local, Local, Local)}. In either overload the first {@code Local} parameter
673e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * is where the result will be sent; the other {@code Local} parameters are the
683e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * inputs.
69d6c77efc0b187577dd7956070adfc7c335f65698Jesse Wilson *
70ff561a27def418f8c19a36df5fec727dfc8bb17aJesse Wilson * <h3>Comparisons</h3>
71d6c77efc0b187577dd7956070adfc7c335f65698Jesse Wilson * There are three different comparison operations each with different
72d6c77efc0b187577dd7956070adfc7c335f65698Jesse Wilson * constraints:
73d6c77efc0b187577dd7956070adfc7c335f65698Jesse Wilson * <ul>
743e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson *     <li>{@link #compareLongs compareLongs()} compares two locals each
75d6c77efc0b187577dd7956070adfc7c335f65698Jesse Wilson *         containing a {@code long} primitive. This is the only operation that
76d6c77efc0b187577dd7956070adfc7c335f65698Jesse Wilson *         can compare longs. The result of the comparison is written to another
77d6c77efc0b187577dd7956070adfc7c335f65698Jesse Wilson *         {@code int} local.</li>
783e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson *     <li>{@link #compareFloatingPoint compareFloatingPoint()} compares two
79d6c77efc0b187577dd7956070adfc7c335f65698Jesse Wilson *         locals; both {@code float} primitives or both {@code double}
80d6c77efc0b187577dd7956070adfc7c335f65698Jesse Wilson *         primitives. This is the only operation that can compare floating
81d6c77efc0b187577dd7956070adfc7c335f65698Jesse Wilson *         point values. This comparison takes an extra parameter that sets
82d6c77efc0b187577dd7956070adfc7c335f65698Jesse Wilson *         the desired result if either parameter is {@code NaN}. The result of
83d6c77efc0b187577dd7956070adfc7c335f65698Jesse Wilson *         the comparison is wrtten to another {@code int} local.
843e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson *     <li>{@link #compare compare()} compares two locals. The {@link
853e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson *         Comparison#EQ} and {@link Comparison#NE} options compare either
863e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson *         {@code int} primitives or references. The other options compare only
873e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson *         {@code int} primitives. This comparison takes a {@link Label} that
883e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson *         will be jumped to if the comparison is true. If the comparison is
893e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson *         false the next instruction in sequence will be executed.
90d6c77efc0b187577dd7956070adfc7c335f65698Jesse Wilson * </ul>
91d6c77efc0b187577dd7956070adfc7c335f65698Jesse Wilson * There's no single operation to compare longs and jump, or to compare ints and
92d6c77efc0b187577dd7956070adfc7c335f65698Jesse Wilson * store the result in a local. Accomplish these goals by chaining multiple
93d6c77efc0b187577dd7956070adfc7c335f65698Jesse Wilson * operations together.
94d6c77efc0b187577dd7956070adfc7c335f65698Jesse Wilson *
95ff561a27def418f8c19a36df5fec727dfc8bb17aJesse Wilson * <h3>Branches, Labels and Returns</h3>
96ff561a27def418f8c19a36df5fec727dfc8bb17aJesse Wilson * Basic control flow is expressed using jumps and labels. Each label must be
97ff561a27def418f8c19a36df5fec727dfc8bb17aJesse Wilson * marked exactly once and may be jumped to any number of times. Create a label
983e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * using its constructor: {@code new Label()}, and mark it using {@link #mark
993e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * mark(Label)}. All jumps to a label will execute instructions starting from
1003e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * that label. You can jump to a label that hasn't yet been marked (jumping
1013e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * forward) or to a label that has already been marked (jumping backward). Jump
1023e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * unconditionally with {@link #jump jump(Label)} or conditionally based on a
1033e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * comparison using {@link #compare compare()}.
104ff561a27def418f8c19a36df5fec727dfc8bb17aJesse Wilson *
10595689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy * <p>Most methods should contain a return instruction. Void methods
1063e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * should use {@link #returnVoid()}; non-void methods should use {@link
1073e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * #returnValue returnValue()} with a local whose return type matches the
1083e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * method's return type. Constructors are considered void methods and should
1093e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * call {@link #returnVoid()}. Methods may make multiple returns. Methods
1103e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * containing no return statements must either loop infinitely or throw
1113e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * unconditionally; it is not legal to end a sequence of instructions without a
1123e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * jump, return or throw.
113d6c77efc0b187577dd7956070adfc7c335f65698Jesse Wilson *
114ff561a27def418f8c19a36df5fec727dfc8bb17aJesse Wilson * <h3>Throwing and Catching</h3>
115ff561a27def418f8c19a36df5fec727dfc8bb17aJesse Wilson * This API uses labels to handle thrown exceptions, errors and throwables. Call
1163e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * {@link #addCatchClause addCatchClause()} to register the target label and
1173e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * throwable class. All statements that follow will jump to that catch clause if
1183e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * they throw a {@link Throwable} assignable to that type. Use {@link
1193e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * #removeCatchClause removeCatchClause()} to unregister the throwable class.
12097b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson *
121ff561a27def418f8c19a36df5fec727dfc8bb17aJesse Wilson * <p>Throw an throwable by first assigning it to a local and then calling
1223e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * {@link #throwValue throwValue()}. Control flow will jump to the nearest label
1233e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * assigned to a type assignable to the thrown type. In this context, "nearest"
1243e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * means the label requiring the fewest stack frames to be popped.
125d6c77efc0b187577dd7956070adfc7c335f65698Jesse Wilson *
126ff561a27def418f8c19a36df5fec727dfc8bb17aJesse Wilson * <h3>Calling methods</h3>
127ff561a27def418f8c19a36df5fec727dfc8bb17aJesse Wilson * A method's caller must know its return type, name, parameters, and invoke
1283e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * kind. Lookup a method on a type using {@link TypeId#getMethod
1293e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * TypeId.getMethod()}. This is more onerous than Java language invokes, which
1303e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * can infer the target method using the target object and parameters. There are
1313e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * four invoke kinds:
132ff561a27def418f8c19a36df5fec727dfc8bb17aJesse Wilson * <ul>
1333e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson *     <li>{@link #invokeStatic invokeStatic()} is used for static methods.</li>
1343e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson *     <li>{@link #invokeDirect invokeDirect()} is used for private instance
1353e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson *         methods and for constructors to call their superclass's
1363e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson *         constructor.</li>
1373e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson *     <li>{@link #invokeInterface invokeInterface()} is used to invoke a method
1383e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson *         whose declaring type is an interface.</li>
1393e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson *     <li>{@link #invokeVirtual invokeVirtual()} is used to invoke any other
1403e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson *         method. The target must not be static, private, a constructor, or an
1413e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson *         interface method.</li>
1423e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson *     <li>{@link #invokeSuper invokeSuper()} is used to invoke the closest
1433e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson *         superclass's virtual method. The target must not be static, private,
1443e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson *         a constructor method, or an interface method.</li>
1453e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson *     <li>{@link #newInstance newInstance()} is used to invoke a
1463e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson *         constructor.</li>
147ff561a27def418f8c19a36df5fec727dfc8bb17aJesse Wilson * </ul>
148ff561a27def418f8c19a36df5fec727dfc8bb17aJesse Wilson * All invoke methods take a local for the return value. For void methods this
149ff561a27def418f8c19a36df5fec727dfc8bb17aJesse Wilson * local is unused and may be null.
150d6c77efc0b187577dd7956070adfc7c335f65698Jesse Wilson *
151ff561a27def418f8c19a36df5fec727dfc8bb17aJesse Wilson * <h3>Field Access</h3>
1523e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * Read static fields using {@link #sget sget()}; write them using {@link
1533e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * #sput sput()}. For instance values you'll need to specify the declaring
1543e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * instance; use {@link #getThis getThis()} in an instance method to use {@code
1553e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * this}. Read instance values using {@link #iget iget()} and write them with
1563e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * {@link #iput iput()}.
157d6c77efc0b187577dd7956070adfc7c335f65698Jesse Wilson *
158ff561a27def418f8c19a36df5fec727dfc8bb17aJesse Wilson * <h3>Array Access</h3>
1593e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * Allocate an array using {@link #newArray newArray()}. Read an array's length
1603e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * with {@link #arrayLength arrayLength()} and its elements with {@link #aget
1613e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * aget()}. Write an array's elements with {@link #aput aput()}.
162d6c77efc0b187577dd7956070adfc7c335f65698Jesse Wilson *
163ff561a27def418f8c19a36df5fec727dfc8bb17aJesse Wilson * <h3>Types</h3>
1643e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * Use {@link #cast cast()} to perform either a <strong>numeric cast</strong> or
1653e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * a <strong>type cast</strong>. Interrogate the type of a value in a local
1663e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * using {@link #instanceOfType instanceOfType()}.
1675624228626d7cdf206de25a6981ba8107be61057Jesse Wilson *
1685624228626d7cdf206de25a6981ba8107be61057Jesse Wilson * <h3>Synchronization</h3>
1693e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * Acquire a monitor using {@link #monitorEnter monitorEnter()}; release it with
1703e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * {@link #monitorExit monitorExit()}. It is the caller's responsibility to
1713e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * guarantee that enter and exit calls are balanced, even in the presence of
1723e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson * exceptions thrown.
1735624228626d7cdf206de25a6981ba8107be61057Jesse Wilson *
1745624228626d7cdf206de25a6981ba8107be61057Jesse Wilson * <strong>Warning:</strong> Even if a method has the {@code synchronized} flag,
1755624228626d7cdf206de25a6981ba8107be61057Jesse Wilson * dex requires instructions to acquire and release monitors manually. A method
1765624228626d7cdf206de25a6981ba8107be61057Jesse Wilson * declared with {@link java.lang.reflect.Modifier#SYNCHRONIZED SYNCHRONIZED}
1775624228626d7cdf206de25a6981ba8107be61057Jesse Wilson * but without manual calls to {@code monitorEnter()} and {@code monitorExit()}
1785624228626d7cdf206de25a6981ba8107be61057Jesse Wilson * will not be synchronized when executed.
179b0f6ea8cec29bd1b2453e8fd15d9c6f65ca3ea2cJesse Wilson */
180579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonpublic final class Code {
181579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final MethodId<?, ?> method;
182579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
183579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * All allocated labels. Although the order of the labels in this list
184579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * shouldn't impact behavior, it is used to determine basic block indices.
185579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
186579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final List<Label> labels = new ArrayList<Label>();
187579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
188579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
189579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * The label currently receiving instructions. This is null if the most
190579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * recent instruction was a return or goto.
191579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
192579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private Label currentLabel;
193579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
194579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** true once we've fixed the positions of the parameter registers */
195579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private boolean localsInitialized;
196579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
197579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final Local<?> thisLocal;
198b3b96215f3dcbacb3f0d86780ac635cfc14ae9cfJesse Wilson
199b3b96215f3dcbacb3f0d86780ac635cfc14ae9cfJesse Wilson    /**
200b3b96215f3dcbacb3f0d86780ac635cfc14ae9cfJesse Wilson     * The parameters on this method. If this is non-static, the first parameter
201b3b96215f3dcbacb3f0d86780ac635cfc14ae9cfJesse Wilson     * is 'thisLocal' and we have to offset the user's indices by one.
202b3b96215f3dcbacb3f0d86780ac635cfc14ae9cfJesse Wilson     */
203579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final List<Local<?>> parameters = new ArrayList<Local<?>>();
204579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final List<Local<?>> locals = new ArrayList<Local<?>>();
205579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private SourcePosition sourcePosition = SourcePosition.NO_INFO;
2060e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson    private final List<TypeId<?>> catchTypes = new ArrayList<TypeId<?>>();
207579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final List<Label> catchLabels = new ArrayList<Label>();
208579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private StdTypeList catches = StdTypeList.EMPTY;
209579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
210ab220f004db90fa94ef9349ca1adde5f89012e8dJesse Wilson    Code(DexMaker.MethodDeclaration methodDeclaration) {
211579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.method = methodDeclaration.method;
212b3b96215f3dcbacb3f0d86780ac635cfc14ae9cfJesse Wilson        if (methodDeclaration.isStatic()) {
213b3b96215f3dcbacb3f0d86780ac635cfc14ae9cfJesse Wilson            thisLocal = null;
214b3b96215f3dcbacb3f0d86780ac635cfc14ae9cfJesse Wilson        } else {
215b3b96215f3dcbacb3f0d86780ac635cfc14ae9cfJesse Wilson            thisLocal = Local.get(this, method.declaringType);
216b3b96215f3dcbacb3f0d86780ac635cfc14ae9cfJesse Wilson            parameters.add(thisLocal);
217b3b96215f3dcbacb3f0d86780ac635cfc14ae9cfJesse Wilson        }
2180e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        for (TypeId<?> parameter : method.parameters.types) {
219579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            parameters.add(Local.get(this, parameter));
220579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
22123abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson        this.currentLabel = new Label();
22223abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson        adopt(this.currentLabel);
223579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.currentLabel.marked = true;
224579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
225579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
2263e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson    /**
2273e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * Allocates a new local variable of type {@code type}. It is an error to
2283e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * allocate a local after instructions have been emitted.
2293e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     */
2300e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson    public <T> Local<T> newLocal(TypeId<T> type) {
231579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (localsInitialized) {
232579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new IllegalStateException("Cannot allocate locals after adding instructions");
233579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
234579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Local<T> result = Local.get(this, type);
235579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        locals.add(result);
236579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return result;
237579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
238579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
2393e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson    /**
2403e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * Returns the local for the parameter at index {@code index} and of type
2413e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * {@code type}.
2423e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     */
2430e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson    public <T> Local<T> getParameter(int index, TypeId<T> type) {
244b3b96215f3dcbacb3f0d86780ac635cfc14ae9cfJesse Wilson        if (thisLocal != null) {
245b3b96215f3dcbacb3f0d86780ac635cfc14ae9cfJesse Wilson            index++; // adjust for the hidden 'this' parameter
246b3b96215f3dcbacb3f0d86780ac635cfc14ae9cfJesse Wilson        }
247579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return coerce(parameters.get(index), type);
248579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
249579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
2503e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson    /**
2513e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * Returns the local for {@code this} of type {@code type}. It is an error
2523e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * to call {@code getThis()} if this is a static method.
2533e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     */
2540e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson    public <T> Local<T> getThis(TypeId<T> type) {
255579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (thisLocal == null) {
256579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new IllegalStateException("static methods cannot access 'this'");
257579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
258579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return coerce(thisLocal, type);
259579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
260579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
261579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    @SuppressWarnings("unchecked") // guarded by an equals check
2620e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson    private <T> Local<T> coerce(Local<?> local, TypeId<T> expectedType) {
263579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (!local.type.equals(expectedType)) {
264579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new IllegalArgumentException(
265579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    "requested " + expectedType + " but was " + local.type);
266579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
267579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return (Local<T>) local;
268579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
269579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
270579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
271579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Assigns registers to locals. From the spec:
272579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *  "the N arguments to a method land in the last N registers of the
273579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *   method's invocation frame, in order. Wide arguments consume two
274579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *   registers. Instance methods are passed a this reference as their
275579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *   first argument."
276579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
277579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * In addition to assigning registers to each of the locals, this creates
278579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * instructions to move parameters into their initial registers. These
279579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * instructions are inserted before the code's first real instruction.
280579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
281579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    void initializeLocals() {
282579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (localsInitialized) {
283579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new AssertionError();
284579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
285579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        localsInitialized = true;
286579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
287579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int reg = 0;
288579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (Local<?> local : locals) {
289579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            reg += local.initialize(reg);
290579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
291579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int firstParamReg = reg;
292579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        List<Insn> moveParameterInstructions = new ArrayList<Insn>();
293579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (Local<?> local : parameters) {
294579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            CstInteger paramConstant = CstInteger.make(reg - firstParamReg);
295579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            reg += local.initialize(reg);
296579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            moveParameterInstructions.add(new PlainCstInsn(Rops.opMoveParam(local.type.ropType),
297579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    sourcePosition, local.spec(), RegisterSpecList.EMPTY, paramConstant));
298579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
299579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        labels.get(0).instructions.addAll(0, moveParameterInstructions);
300579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
301579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
302b3b96215f3dcbacb3f0d86780ac635cfc14ae9cfJesse Wilson    /**
303b3b96215f3dcbacb3f0d86780ac635cfc14ae9cfJesse Wilson     * Returns the number of registers to hold the parameters. This includes the
304b3b96215f3dcbacb3f0d86780ac635cfc14ae9cfJesse Wilson     * 'this' parameter if it exists.
305b3b96215f3dcbacb3f0d86780ac635cfc14ae9cfJesse Wilson     */
306579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    int paramSize() {
307579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int result = 0;
308579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (Local<?> local : parameters) {
309579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            result += local.size();
310579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
311579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return result;
312579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
313579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
314579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    // labels
315579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
316579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
31723abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson     * Assigns {@code target} to this code.
318579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
31923abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson    private void adopt(Label target) {
32023abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson        if (target.code == this) {
32123abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson            return; // already adopted
32223abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson        }
32323abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson        if (target.code != null) {
32423abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson            throw new IllegalArgumentException("Cannot adopt label; it belongs to another Code");
32523abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson        }
32623abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson        target.code = this;
32723abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson        labels.add(target);
328579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
329579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
330579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
331579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Start defining instructions for the named label.
332579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
333579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void mark(Label label) {
33423abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson        adopt(label);
335579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (label.marked) {
336579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new IllegalStateException("already marked");
337579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
338579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        label.marked = true;
339579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (currentLabel != null) {
340579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            jump(label); // blocks must end with a branch, return or throw
341579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
342579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        currentLabel = label;
343579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
344579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
3453e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson    /**
3463e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * Transfers flow control to the instructions at {@code target}. It is an
3473e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * error to jump to a label not marked on this {@code Code}.
3483e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     */
349579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void jump(Label target) {
35023abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson        adopt(target);
351579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        addInstruction(new PlainInsn(Rops.GOTO, sourcePosition, null, RegisterSpecList.EMPTY),
352579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                target);
353579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
354579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
3553e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson    /**
3563e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * Registers {@code catchClause} as a branch target for all instructions
3573e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * in this frame that throw a class assignable to {@code toCatch}. This
3583e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * includes methods invoked from this frame. Deregister the clause using
3593e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * {@link #removeCatchClause removeCatchClause()}. It is an error to
3603e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * register a catch clause without also {@link #mark marking it} in the same
3613e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * {@code Code} instance.
3623e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     */
3633e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson    public void addCatchClause(TypeId<? extends Throwable> toCatch, Label catchClause) {
3643e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson        if (catchTypes.contains(toCatch)) {
3653e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson            throw new IllegalArgumentException("Already caught: " + toCatch);
366579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
36723abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson        adopt(catchClause);
3683e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson        catchTypes.add(toCatch);
369579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        catches = toTypeList(catchTypes);
370579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        catchLabels.add(catchClause);
371579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
372579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
3733e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson    /**
3743e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * Deregisters the catch clause label for {@code toCatch} and returns it.
3753e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     */
3763e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson    public Label removeCatchClause(TypeId<? extends Throwable> toCatch) {
3773e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson        int index = catchTypes.indexOf(toCatch);
378579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (index == -1) {
3793e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson            throw new IllegalArgumentException("No catch clause: " + toCatch);
380579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
381579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        catchTypes.remove(index);
382579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        catches = toTypeList(catchTypes);
383579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return catchLabels.remove(index);
384579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
385579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
3863e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson    /**
3873e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * Throws the throwable in {@code toThrow}.
3883e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     */
3893e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson    public void throwValue(Local<? extends Throwable> toThrow) {
390579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        addInstruction(new ThrowingInsn(Rops.THROW, sourcePosition,
3913e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson                RegisterSpecList.make(toThrow.spec()), catches));
392579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
393579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
3940e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson    private StdTypeList toTypeList(List<TypeId<?>> types) {
395579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        StdTypeList result = new StdTypeList(types.size());
396579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (int i = 0; i < types.size(); i++) {
397579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            result.set(i, types.get(i).ropType);
398579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
399579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return result;
400579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
401579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
402579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private void addInstruction(Insn insn) {
403579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        addInstruction(insn, null);
404579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
405579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
406579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
407579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param branch the branches to follow; interpretation depends on the
408579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *     instruction's branchingness.
409579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
410579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private void addInstruction(Insn insn, Label branch) {
411579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (currentLabel == null || !currentLabel.marked) {
412579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new IllegalStateException("no current label");
413579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
414579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        currentLabel.instructions.add(insn);
415579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
416579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        switch (insn.getOpcode().getBranchingness()) {
417579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        case BRANCH_NONE:
418579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (branch != null) {
419579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                throw new IllegalArgumentException("unexpected branch: " + branch);
420579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
421579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return;
422579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
423579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        case BRANCH_RETURN:
424579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (branch != null) {
425579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                throw new IllegalArgumentException("unexpected branch: " + branch);
426579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
427579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            currentLabel = null;
428579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            break;
429579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
430579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        case BRANCH_GOTO:
431579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (branch == null) {
432579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                throw new IllegalArgumentException("branch == null");
433579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
434579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            currentLabel.primarySuccessor = branch;
435579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            currentLabel = null;
436579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            break;
437579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
438579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        case Rop.BRANCH_IF:
439579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (branch == null) {
440579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                throw new IllegalArgumentException("branch == null");
441579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
442579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            splitCurrentLabel(branch, Collections.<Label>emptyList());
443579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            break;
444579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
445579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        case Rop.BRANCH_THROW:
446579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (branch != null) {
447579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                throw new IllegalArgumentException("unexpected branch: " + branch);
448579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
449579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            splitCurrentLabel(null, new ArrayList<Label>(catchLabels));
450579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            break;
451579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
452579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        default:
453579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new IllegalArgumentException();
454579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
455579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
456579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
457579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
458579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Closes the current label and starts a new one.
459579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
460579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param catchLabels an immutable list of catch labels
461579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
462579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private void splitCurrentLabel(Label alternateSuccessor, List<Label> catchLabels) {
46323abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson        Label newLabel = new Label();
46423abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson        adopt(newLabel);
465579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        currentLabel.primarySuccessor = newLabel;
466579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        currentLabel.alternateSuccessor = alternateSuccessor;
467579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        currentLabel.catchLabels = catchLabels;
468579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        currentLabel = newLabel;
469579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        currentLabel.marked = true;
470579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
471579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
4724838105a39ae6c608c2a0e242ead249d8683a5d0Jesse Wilson    // instructions: locals
473579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
4743e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson    /**
4753e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * Copies the constant value {@code value} to {@code target}. The constant
4763e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * must be a primitive, String, Class, TypeId, or null.
4773e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     */
478579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public <T> void loadConstant(Local<T> target, T value) {
479579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Rop rop = value == null
480579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                ? Rops.CONST_OBJECT_NOTHROW
481579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                : Rops.opConst(target.type.ropType);
482579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (rop.getBranchingness() == BRANCH_NONE) {
483579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            addInstruction(new PlainCstInsn(rop, sourcePosition, target.spec(),
484579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    RegisterSpecList.EMPTY, Constants.getConstant(value)));
485579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } else {
486579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            addInstruction(new ThrowingCstInsn(rop, sourcePosition,
487579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    RegisterSpecList.EMPTY, catches, Constants.getConstant(value)));
488579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            moveResult(target, true);
489579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
490579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
491579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
4924838105a39ae6c608c2a0e242ead249d8683a5d0Jesse Wilson    /**
4934838105a39ae6c608c2a0e242ead249d8683a5d0Jesse Wilson     * Copies the value in {@code source} to {@code target}.
4944838105a39ae6c608c2a0e242ead249d8683a5d0Jesse Wilson     */
4954838105a39ae6c608c2a0e242ead249d8683a5d0Jesse Wilson    public <T> void move(Local<T> target, Local<T> source) {
4964838105a39ae6c608c2a0e242ead249d8683a5d0Jesse Wilson        addInstruction(new PlainInsn(Rops.opMove(source.type.ropType),
4974838105a39ae6c608c2a0e242ead249d8683a5d0Jesse Wilson                sourcePosition, target.spec(), source.spec()));
4984838105a39ae6c608c2a0e242ead249d8683a5d0Jesse Wilson    }
4994838105a39ae6c608c2a0e242ead249d8683a5d0Jesse Wilson
500d6c77efc0b187577dd7956070adfc7c335f65698Jesse Wilson    // instructions: unary and binary
501579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
5023e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson    /**
5033e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * Executes {@code op} and sets {@code target} to the result.
5043e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     */
505b0f6ea8cec29bd1b2453e8fd15d9c6f65ca3ea2cJesse Wilson    public <T> void op(UnaryOp op, Local<T> target, Local<T> source) {
50697b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson        addInstruction(new PlainInsn(op.rop(source.type), sourcePosition,
50797b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson                target.spec(), source.spec()));
508579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
509579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
5103e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson    /**
51195689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy     * Executes {@code op} and sets {@code target} to the result. For most
51295689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy     * binary operations, the types of {@code a} and {@code b} must be the same.
51395689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy     * Shift operations (like {@link BinaryOp#SHIFT_LEFT}) require {@code b} to
51495689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy     * be an {@code int}, even when {@code a} is a {@code long}.
5153e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     */
51695689a700bfea5e2d78380a442fc2903cc40a3f2Mark Brophy    public <T1, T2> void op(BinaryOp op, Local<T1> target, Local<T1> a, Local<T2> b) {
517579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Rop rop = op.rop(StdTypeList.make(a.type.ropType, b.type.ropType));
518579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        RegisterSpecList sources = RegisterSpecList.make(a.spec(), b.spec());
519579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
520579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (rop.getBranchingness() == BRANCH_NONE) {
521579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            addInstruction(new PlainInsn(rop, sourcePosition, target.spec(), sources));
522579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } else {
523579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            addInstruction(new ThrowingInsn(rop, sourcePosition, sources, catches));
524579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            moveResult(target, true);
525579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
526579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
527579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
528579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    // instructions: branches
529579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
530579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
531d6c77efc0b187577dd7956070adfc7c335f65698Jesse Wilson     * Compare ints or references. If the comparison is true, execution jumps to
532d6c77efc0b187577dd7956070adfc7c335f65698Jesse Wilson     * {@code trueLabel}. If it is false, execution continues to the next
533d6c77efc0b187577dd7956070adfc7c335f65698Jesse Wilson     * instruction.
534579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
5350e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson    public <T> void compare(Comparison comparison, Label trueLabel, Local<T> a, Local<T> b) {
53623abc2fe89ec3713645d64bdb74415a9090084f4Jesse Wilson        adopt(trueLabel);
537d6c77efc0b187577dd7956070adfc7c335f65698Jesse Wilson        // TODO: ops to compare with zero/null: just omit the 2nd local in StdTypeList.make()
538579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Rop rop = comparison.rop(StdTypeList.make(a.type.ropType, b.type.ropType));
539579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        addInstruction(new PlainInsn(rop, sourcePosition, null,
540579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                RegisterSpecList.make(a.spec(), b.spec())), trueLabel);
541579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
542579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
543579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
5444838105a39ae6c608c2a0e242ead249d8683a5d0Jesse Wilson     * Compare floats or doubles. This stores -1 in {@code target} if {@code
5454838105a39ae6c608c2a0e242ead249d8683a5d0Jesse Wilson     * a < b}, 0 in {@code target} if {@code a == b} and 1 in target if {@code
5464838105a39ae6c608c2a0e242ead249d8683a5d0Jesse Wilson     * a > b}. This stores {@code nanValue} in {@code target} if either value
5474838105a39ae6c608c2a0e242ead249d8683a5d0Jesse Wilson     * is {@code NaN}.
548579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
549d6c77efc0b187577dd7956070adfc7c335f65698Jesse Wilson    public <T extends Number> void compareFloatingPoint(
550d6c77efc0b187577dd7956070adfc7c335f65698Jesse Wilson            Local<Integer> target, Local<T> a, Local<T> b, int nanValue) {
551579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Rop rop;
552579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (nanValue == 1) {
553579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            rop = Rops.opCmpg(a.type.ropType);
554579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } else if (nanValue == -1) {
555579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            rop = Rops.opCmpl(a.type.ropType);
556579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } else {
557579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new IllegalArgumentException("expected 1 or -1 but was " + nanValue);
558579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
559579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        addInstruction(new PlainInsn(rop, sourcePosition, target.spec(),
560579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                RegisterSpecList.make(a.spec(), b.spec())));
561579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
562579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
563579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
5644838105a39ae6c608c2a0e242ead249d8683a5d0Jesse Wilson     * Compare longs. This stores -1 in {@code target} if {@code
5654838105a39ae6c608c2a0e242ead249d8683a5d0Jesse Wilson     * a < b}, 0 in {@code target} if {@code a == b} and 1 in target if {@code
5664838105a39ae6c608c2a0e242ead249d8683a5d0Jesse Wilson     * a > b}.
567579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
568d6c77efc0b187577dd7956070adfc7c335f65698Jesse Wilson    public void compareLongs(Local<Integer> target, Local<Long> a, Local<Long> b) {
569579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        addInstruction(new PlainInsn(Rops.CMPL_LONG, sourcePosition, target.spec(),
570579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                RegisterSpecList.make(a.spec(), b.spec())));
571579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
572579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
573579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    // instructions: fields
574579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
5753e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson    /**
5763e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * Copies the value in instance field {@code fieldId} of {@code instance} to
5773e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * {@code target}.
5783e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     */
5790e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson    public <D, V> void iget(FieldId<D, V> fieldId, Local<V> target, Local<D> instance) {
580579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        addInstruction(new ThrowingCstInsn(Rops.opGetField(target.type.ropType), sourcePosition,
581579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                RegisterSpecList.make(instance.spec()), catches, fieldId.constant));
582579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        moveResult(target, true);
583579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
584579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
5853e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson    /**
5863e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * Copies the value in {@code source} to the instance field {@code fieldId}
5873e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * of {@code instance}.
5883e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     */
5893e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson   public <D, V> void iput(FieldId<D, V> fieldId, Local<D> instance, Local<V> source) {
590579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        addInstruction(new ThrowingCstInsn(Rops.opPutField(source.type.ropType), sourcePosition,
591579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                RegisterSpecList.make(source.spec(), instance.spec()), catches, fieldId.constant));
592579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
593579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
5943e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson    /**
5958ec4b1db3afa51730508be7064d2111b723ac2cdHugo Hudson     * Copies the value in the static field {@code fieldId} to {@code target}.
5963e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     */
597579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public <V> void sget(FieldId<?, V> fieldId, Local<V> target) {
598579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        addInstruction(new ThrowingCstInsn(Rops.opGetStatic(target.type.ropType), sourcePosition,
599579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                RegisterSpecList.EMPTY, catches, fieldId.constant));
600579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        moveResult(target, true);
601579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
602579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
6033e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson    /**
6043e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * Copies the value in {@code source} to the static field {@code fieldId}.
6053e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     */
606579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public <V> void sput(FieldId<?, V> fieldId, Local<V> source) {
607579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        addInstruction(new ThrowingCstInsn(Rops.opPutStatic(source.type.ropType), sourcePosition,
608579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                RegisterSpecList.make(source.spec()), catches, fieldId.constant));
609579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
610579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
611579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    // instructions: invoke
612579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
6133e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson    /**
6143e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * Calls the constructor {@code constructor} using {@code args} and assigns
6153e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * the new instance to {@code target}.
6163e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     */
617579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public <T> void newInstance(Local<T> target, MethodId<T, Void> constructor, Local<?>... args) {
618579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (target == null) {
619579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new IllegalArgumentException();
620579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
621579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        addInstruction(new ThrowingCstInsn(Rops.NEW_INSTANCE, sourcePosition,
622579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                RegisterSpecList.EMPTY, catches, constructor.declaringType.constant));
623579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        moveResult(target, true);
624579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        invokeDirect(constructor, null, target, args);
625579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
626579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
6273e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson    /**
6283e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * Calls the static method {@code method} using {@code args} and assigns the
6293e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * result to {@code target}.
6303e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     *
6313e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * @param target the local to receive the method's return value, or {@code
6323e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     *     null} if the return type is {@code void} or if its value not needed.
6333e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     */
634579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public <R> void invokeStatic(MethodId<?, R> method, Local<? super R> target, Local<?>... args) {
635579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        invoke(Rops.opInvokeStatic(method.prototype(true)), method, target, null, args);
636579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
637579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
6383e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson    /**
6393e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * Calls the non-private instance method {@code method} of {@code instance}
6403e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * using {@code args} and assigns the result to {@code target}.
6413e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     *
6423e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * @param method a non-private, non-static, method declared on a class. May
6433e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     *     not be an interface method or a constructor.
6443e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * @param target the local to receive the method's return value, or {@code
6453e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     *     null} if the return type is {@code void} or if its value not needed.
6463e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     */
647579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public <D, R> void invokeVirtual(MethodId<D, R> method, Local<? super R> target,
6483e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson            Local<? extends D> instance, Local<?>... args) {
6493e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson        invoke(Rops.opInvokeVirtual(method.prototype(true)), method, target, instance, args);
650579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
651579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
6523e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson    /**
6533e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * Calls {@code method} of {@code instance} using {@code args} and assigns
6543e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * the result to {@code target}.
6553e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     *
6563e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * @param method either a private method or the superclass's constructor in
6573e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     *     a constructor's call to {@code super()}.
6583e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * @param target the local to receive the method's return value, or {@code
6593e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     *     null} if the return type is {@code void} or if its value not needed.
6603e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     */
661579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public <D, R> void invokeDirect(MethodId<D, R> method, Local<? super R> target,
6623e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson            Local<? extends D> instance, Local<?>... args) {
6633e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson        invoke(Rops.opInvokeDirect(method.prototype(true)), method, target, instance, args);
664579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
665579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
6663e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson    /**
6673e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * Calls the closest superclass's virtual method {@code method} of {@code
6683e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * instance} using {@code args} and assigns the result to {@code target}.
6693e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     *
6703e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * @param target the local to receive the method's return value, or {@code
6713e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     *     null} if the return type is {@code void} or if its value not needed.
6723e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     */
673579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public <D, R> void invokeSuper(MethodId<D, R> method, Local<? super R> target,
6743e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson            Local<? extends D> instance, Local<?>... args) {
6753e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson        invoke(Rops.opInvokeSuper(method.prototype(true)), method, target, instance, args);
676579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
677579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
6783e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson    /**
6793e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * Calls the interface method {@code method} of {@code instance} using
6803e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * {@code args} and assigns the result to {@code target}.
6813e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     *
6823e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * @param method a method declared on an interface.
6833e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * @param target the local to receive the method's return value, or {@code
6843e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     *     null} if the return type is {@code void} or if its value not needed.
6853e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     */
686579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public <D, R> void invokeInterface(MethodId<D, R> method, Local<? super R> target,
6873e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson            Local<? extends D> instance, Local<?>... args) {
6883e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson        invoke(Rops.opInvokeInterface(method.prototype(true)), method, target, instance, args);
689579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
690579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
691579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private <D, R> void invoke(Rop rop, MethodId<D, R> method, Local<? super R> target,
692579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            Local<? extends D> object, Local<?>... args) {
693579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        addInstruction(new ThrowingCstInsn(rop, sourcePosition, concatenate(object, args),
694579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                catches, method.constant));
695579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (target != null) {
696579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            moveResult(target, false);
697579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
698579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
699579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
700579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    // instructions: types
701579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
7023e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson    /**
7033e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * Tests if the value in {@code source} is assignable to {@code type}. If it
7043e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * is, {@code target} is assigned to 1; otherwise {@code target} is assigned
7053e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * to 0.
7063e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     */
7070e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson    public void instanceOfType(Local<?> target, Local<?> source, TypeId<?> type) {
708579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        addInstruction(new ThrowingCstInsn(Rops.INSTANCE_OF, sourcePosition,
709579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                RegisterSpecList.make(source.spec()), catches, type.constant));
710579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        moveResult(target, true);
711579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
712579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
71397b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson    /**
71497b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson     * Performs either a numeric cast or a type cast.
71597b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson     *
71697b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson     * <h3>Numeric Casts</h3>
71797b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson     * Converts a primitive to a different representation. Numeric casts may
71897b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson     * be lossy. For example, converting the double {@code 1.8d} to an integer
71997b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson     * yields {@code 1}, losing the fractional part. Converting the integer
72097b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson     * {@code 0x12345678} to a short yields {@code 0x5678}, losing the high
72197b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson     * bytes. The following numeric casts are supported:
72297b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson     *
723b8a5896885d4da2b798888b688a46df1adbf5b89Paul Duffin     * <p><table border="1" summary="Supported Numeric Casts">
72497b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson     * <tr><th>From</th><th>To</th></tr>
72597b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson     * <tr><td>int</td><td>byte, char, short, long, float, double</td></tr>
72697b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson     * <tr><td>long</td><td>int, float, double</td></tr>
72797b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson     * <tr><td>float</td><td>int, long, double</td></tr>
72897b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson     * <tr><td>double</td><td>int, long, float</td></tr>
72997b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson     * </table>
73097b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson     *
73197b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson     * <p>For some primitive conversions it will be necessary to chain multiple
73297b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson     * cast operations. For example, to go from float to short one would first
73397b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson     * cast float to int and then int to short.
73497b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson     *
73597b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson     * <p>Numeric casts never throw {@link ClassCastException}.
73697b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson     *
73797b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson     * <h3>Type Casts</h3>
73897b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson     * Checks that a reference value is assignable to the target type. If it is
73997b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson     * assignable it is copied to the target local. If it is not assignable a
74097b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson     * {@link ClassCastException} is thrown.
74197b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson     */
74297b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson    public void cast(Local<?> target, Local<?> source) {
74397b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson        if (source.getType().ropType.isReference()) {
74497b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson            addInstruction(new ThrowingCstInsn(Rops.CHECK_CAST, sourcePosition,
74597b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson                    RegisterSpecList.make(source.spec()), catches, target.type.constant));
74697b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson            moveResult(target, true);
74797b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson        } else {
74897b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson            addInstruction(new PlainInsn(getCastRop(source.type.ropType, target.type.ropType),
74997b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson                    sourcePosition, target.spec(), source.spec()));
75097b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson        }
75197b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson    }
75297b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson
75397b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson    private Rop getCastRop(com.android.dx.rop.type.Type sourceType,
75497b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson            com.android.dx.rop.type.Type targetType) {
75597b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson        if (sourceType.getBasicType() == BT_INT) {
75697b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson            switch (targetType.getBasicType()) {
75797b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson            case BT_SHORT:
75897b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson                return Rops.TO_SHORT;
75997b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson            case BT_CHAR:
76097b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson                return Rops.TO_CHAR;
76197b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson            case BT_BYTE:
76297b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson                return Rops.TO_BYTE;
76397b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson            }
76497b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson        }
76597b0be6b3da9df87e9026f880b0b0bffc7242450Jesse Wilson        return Rops.opConv(targetType, sourceType);
766579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
767579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
768579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    // instructions: arrays
769579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
7703e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson    /**
7713e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * Sets {@code target} to the length of the array in {@code array}.
7723e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     */
7730e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson    public <T> void arrayLength(Local<Integer> target, Local<T> array) {
774579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        addInstruction(new ThrowingInsn(Rops.ARRAY_LENGTH, sourcePosition,
775579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                RegisterSpecList.make(array.spec()), catches));
776579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        moveResult(target, true);
777579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
778579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
7793e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson    /**
7803e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * Assigns {@code target} to a newly allocated array of length {@code
7813e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * length}. The array's type is the same as {@code target}'s type.
7823e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     */
7830e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson    public <T> void newArray(Local<T> target, Local<Integer> length) {
784579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        addInstruction(new ThrowingCstInsn(Rops.opNewArray(target.type.ropType), sourcePosition,
785579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                RegisterSpecList.make(length.spec()), catches, target.type.constant));
786579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        moveResult(target, true);
787579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
788579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
7893e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson    /**
7908ec4b1db3afa51730508be7064d2111b723ac2cdHugo Hudson     * Assigns the element at {@code index} in {@code array} to {@code target}.
7913e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     */
7920e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson    public void aget(Local<?> target, Local<?> array, Local<Integer> index) {
793579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        addInstruction(new ThrowingInsn(Rops.opAget(target.type.ropType), sourcePosition,
794579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                RegisterSpecList.make(array.spec(), index.spec()), catches));
795579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        moveResult(target, true);
796579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
797579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
7983e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson    /**
7998ec4b1db3afa51730508be7064d2111b723ac2cdHugo Hudson     * Assigns {@code source} to the element at {@code index} in {@code array}.
8003e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     */
801579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void aput(Local<?> array, Local<Integer> index, Local<?> source) {
802579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        addInstruction(new ThrowingInsn(Rops.opAput(source.type.ropType), sourcePosition,
803579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                RegisterSpecList.make(source.spec(), array.spec(), index.spec()), catches));
804579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
805579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
806579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    // instructions: return
807579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
8083e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson    /**
8093e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * Returns from a {@code void} method. After a return it is an error to
8103e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * define further instructions after a return without first {@link #mark
8113e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * marking} an existing unmarked label.
8123e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     */
813579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void returnVoid() {
8140e49fb9243b7463835ab80ef7cc62435f55846ceJesse Wilson        if (!method.returnType.equals(TypeId.VOID)) {
815579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new IllegalArgumentException("declared " + method.returnType
816579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    + " but returned void");
817579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
818579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        addInstruction(new PlainInsn(Rops.RETURN_VOID, sourcePosition, null,
819579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                RegisterSpecList.EMPTY));
820579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
821579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
8223e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson    /**
8233e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * Returns the value in {@code result} to the calling method. After a return
8243e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * it is an error to define further instructions after a return without
8253e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * first {@link #mark marking} an existing unmarked label.
8263e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     */
827579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void returnValue(Local<?> result) {
828579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (!result.type.equals(method.returnType)) {
829579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            // TODO: this is probably too strict.
830579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new IllegalArgumentException("declared " + method.returnType
831579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    + " but returned " + result.type);
832579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
833579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        addInstruction(new PlainInsn(Rops.opReturn(result.type.ropType), sourcePosition,
834579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                null, RegisterSpecList.make(result.spec())));
835579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
836579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
837579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private void moveResult(Local<?> target, boolean afterNonInvokeThrowingInsn) {
838579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Rop rop = afterNonInvokeThrowingInsn
839579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                ? Rops.opMoveResultPseudo(target.type.ropType)
840579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                : Rops.opMoveResult(target.type.ropType);
841579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        addInstruction(new PlainInsn(rop, sourcePosition, target.spec(), RegisterSpecList.EMPTY));
842579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
843579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
8445624228626d7cdf206de25a6981ba8107be61057Jesse Wilson    // instructions; synchronized
8455624228626d7cdf206de25a6981ba8107be61057Jesse Wilson
8463e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson    /**
8473e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * Awaits the lock on {@code monitor}, and acquires it.
8483e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     */
8495624228626d7cdf206de25a6981ba8107be61057Jesse Wilson    public void monitorEnter(Local<?> monitor) {
8505624228626d7cdf206de25a6981ba8107be61057Jesse Wilson        addInstruction(new ThrowingInsn(Rops.MONITOR_ENTER, sourcePosition,
8515624228626d7cdf206de25a6981ba8107be61057Jesse Wilson                RegisterSpecList.make(monitor.spec()), catches));
8525624228626d7cdf206de25a6981ba8107be61057Jesse Wilson    }
8535624228626d7cdf206de25a6981ba8107be61057Jesse Wilson
8543e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson    /**
8553e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     * Releases the held lock on {@code monitor}.
8563e7a2230ec75b59ae9b4aad292f51df2542ced7dJesse Wilson     */
8575624228626d7cdf206de25a6981ba8107be61057Jesse Wilson    public void monitorExit(Local<?> monitor) {
858c3ebe2312233ea0c80bf0bbd282778022bd3582ePaul Duffin        addInstruction(new ThrowingInsn(Rops.MONITOR_EXIT, sourcePosition,
8595624228626d7cdf206de25a6981ba8107be61057Jesse Wilson                RegisterSpecList.make(monitor.spec()), catches));
8605624228626d7cdf206de25a6981ba8107be61057Jesse Wilson    }
8615624228626d7cdf206de25a6981ba8107be61057Jesse Wilson
862579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    // produce BasicBlocks for dex
863579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
864579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    BasicBlockList toBasicBlocks() {
865579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (!localsInitialized) {
866579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            initializeLocals();
867579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
868579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
869579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        cleanUpLabels();
870579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
871579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        BasicBlockList result = new BasicBlockList(labels.size());
872579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (int i = 0; i < labels.size(); i++) {
873579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            result.set(i, labels.get(i).toBasicBlock());
874579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
875579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return result;
876579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
877579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
878579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
879579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Removes empty labels and assigns IDs to non-empty labels.
880579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
881579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private void cleanUpLabels() {
882579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int id = 0;
883579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (Iterator<Label> i = labels.iterator(); i.hasNext();) {
884579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            Label label = i.next();
885579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (label.isEmpty()) {
886579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                i.remove();
887579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            } else {
888579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                label.compact();
889579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                label.id = id++;
890579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
891579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
892579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
893579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
894579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private static RegisterSpecList concatenate(Local<?> first, Local<?>[] rest) {
895579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int offset = (first != null) ? 1 : 0;
896579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        RegisterSpecList result = new RegisterSpecList(offset + rest.length);
897579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (first != null) {
898579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            result.set(0, first.spec());
899579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
900579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (int i = 0; i < rest.length; i++) {
901579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            result.set(i + offset, rest[i].spec());
902579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
903579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return result;
904579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
905579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson}
906