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