Code.java revision 579d7739c53a2707ad711a2d2cae46d7d782f061
1dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org/* 23484964a86451e86dcf04be9bd8c0d76ee04f081rossberg@chromium.org * Copyright (C) 2011 The Android Open Source Project 33484964a86451e86dcf04be9bd8c0d76ee04f081rossberg@chromium.org * 4dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org * Licensed under the Apache License, Version 2.0 (the "License"); 55de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org * you may not use this file except in compliance with the License. 65de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org * You may obtain a copy of the License at 7dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org * 8e31286d471eb2e656a1809383fa16b76053dd673machenbach@chromium.org * http://www.apache.org/licenses/LICENSE-2.0 9dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org * 10dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org * Unless required by applicable law or agreed to in writing, software 11248dd43badb99ffce44eae2d767cda3cefaad521machenbach@chromium.org * distributed under the License is distributed on an "AS IS" BASIS, 12dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org * See the License for the specific language governing permissions and 14dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org * limitations under the License. 15dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org */ 16e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org 17e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.orgpackage com.google.dexmaker; 18dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org 19dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.orgimport com.android.dx.rop.code.BasicBlockList; 20dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.orgimport com.android.dx.rop.code.Insn; 21dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.orgimport com.android.dx.rop.code.PlainCstInsn; 225de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.orgimport com.android.dx.rop.code.PlainInsn; 23dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.orgimport com.android.dx.rop.code.RegisterSpecList; 24dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.orgimport com.android.dx.rop.code.Rop; 25dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.orgimport static com.android.dx.rop.code.Rop.BRANCH_GOTO; 26dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.orgimport static com.android.dx.rop.code.Rop.BRANCH_NONE; 27dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.orgimport static com.android.dx.rop.code.Rop.BRANCH_RETURN; 28dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.orgimport com.android.dx.rop.code.Rops; 29dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.orgimport com.android.dx.rop.code.SourcePosition; 30dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.orgimport com.android.dx.rop.code.ThrowingCstInsn; 31dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.orgimport com.android.dx.rop.code.ThrowingInsn; 32dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.orgimport com.android.dx.rop.cst.CstInteger; 33ada3a6017e603965f87fa34f6e2fa60379e8d697machenbach@chromium.orgimport com.android.dx.rop.type.StdTypeList; 34dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.orgimport static com.android.dx.rop.type.Type.BT_BYTE; 35dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.orgimport static com.android.dx.rop.type.Type.BT_CHAR; 36dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.orgimport static com.android.dx.rop.type.Type.BT_INT; 37dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.orgimport static com.android.dx.rop.type.Type.BT_SHORT; 38dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.orgimport java.util.ArrayList; 39dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.orgimport java.util.Collections; 40dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.orgimport java.util.Iterator; 41dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.orgimport java.util.List; 42dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org 43dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org/** 44dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org * Builds a sequence of instructions. 45dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org */ 46dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.orgpublic final class Code { 47dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org private final MethodId<?, ?> method; 48dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org /** 49dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org * All allocated labels. Although the order of the labels in this list 50dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org * shouldn't impact behavior, it is used to determine basic block indices. 51dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org */ 52dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org private final List<Label> labels = new ArrayList<Label>(); 53dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org 54dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org /** 55dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org * The label currently receiving instructions. This is null if the most 56dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org * recent instruction was a return or goto. 57dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org */ 58dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org private Label currentLabel; 59dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org 60dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org /** true once we've fixed the positions of the parameter registers */ 61dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org private boolean localsInitialized; 62dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org 63dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org private final Local<?> thisLocal; 64e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org private final List<Local<?>> parameters = new ArrayList<Local<?>>(); 65e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org private final List<Local<?>> locals = new ArrayList<Local<?>>(); 66e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org private SourcePosition sourcePosition = SourcePosition.NO_INFO; 67e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org private final List<Type<?>> catchTypes = new ArrayList<Type<?>>(); 68e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org private final List<Label> catchLabels = new ArrayList<Label>(); 69e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org private StdTypeList catches = StdTypeList.EMPTY; 70e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org 71e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org Code(DexGenerator.MethodDeclaration methodDeclaration) { 72dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org this.method = methodDeclaration.method; 73dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org this.thisLocal = methodDeclaration.isStatic() 74dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org ? null 75dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org : Local.get(this, method.declaringType); 76dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org for (Type<?> parameter : method.parameters.types) { 77dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org parameters.add(Local.get(this, parameter)); 78dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } 79dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org this.currentLabel = newLabel(); 80dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org this.currentLabel.marked = true; 81dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } 82dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org 83dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org public <T> Local<T> newLocal(Type<T> type) { 84dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org if (localsInitialized) { 85dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org throw new IllegalStateException("Cannot allocate locals after adding instructions"); 86dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } 87dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org Local<T> result = Local.get(this, type); 88dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org locals.add(result); 89dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org return result; 90dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } 91dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org 92dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org public <T> Local<T> getParameter(int index, Type<T> type) { 93dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org return coerce(parameters.get(index), type); 94dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } 95dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org 96dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org public <T> Local<T> getThis(Type<T> type) { 97dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org if (thisLocal == null) { 98dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org throw new IllegalStateException("static methods cannot access 'this'"); 99dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } 100dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org return coerce(thisLocal, type); 101dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } 102dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org 103dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org @SuppressWarnings("unchecked") // guarded by an equals check 104dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org private <T> Local<T> coerce(Local<?> local, Type<T> expectedType) { 105dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org if (!local.type.equals(expectedType)) { 106dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org throw new IllegalArgumentException( 107dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org "requested " + expectedType + " but was " + local.type); 108dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } 109dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org return (Local<T>) local; 110dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } 111dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org 112dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org /** 113dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org * Assigns registers to locals. From the spec: 114dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org * "the N arguments to a method land in the last N registers of the 115dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org * method's invocation frame, in order. Wide arguments consume two 116dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org * registers. Instance methods are passed a this reference as their 117dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org * first argument." 118dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org * 119dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org * In addition to assigning registers to each of the locals, this creates 120dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org * instructions to move parameters into their initial registers. These 121dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org * instructions are inserted before the code's first real instruction. 122dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org */ 123dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org void initializeLocals() { 124dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org if (localsInitialized) { 125dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org throw new AssertionError(); 126dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } 127dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org localsInitialized = true; 128dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org 129dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org int reg = 0; 130dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org for (Local<?> local : locals) { 131dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org reg += local.initialize(reg); 132dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } 133dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org if (thisLocal != null) { 134dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org reg += thisLocal.initialize(reg); 135dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } 136dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org int firstParamReg = reg; 137dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org 138dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org List<Insn> moveParameterInstructions = new ArrayList<Insn>(); 139dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org for (Local<?> local : parameters) { 140dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org CstInteger paramConstant = CstInteger.make(reg - firstParamReg); 141dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org reg += local.initialize(reg); 142dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org moveParameterInstructions.add(new PlainCstInsn(Rops.opMoveParam(local.type.ropType), 143dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org sourcePosition, local.spec(), RegisterSpecList.EMPTY, paramConstant)); 144dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } 145dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org labels.get(0).instructions.addAll(0, moveParameterInstructions); 146dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } 147dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org 148dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org int paramSize() { 149dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org int result = 0; 150dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org for (Local<?> local : parameters) { 151dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org result += local.size(); 152dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } 153dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org return result; 154dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } 155dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org 156dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org // labels 157dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org 158dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org /** 159dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org * Creates a new label for use as a branch target. The new label must have 160dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org * code attached to it later by calling {@link #mark(Label)}. 161ada3a6017e603965f87fa34f6e2fa60379e8d697machenbach@chromium.org */ 162dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org public Label newLabel() { 163dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org Label result = new Label(); 164dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org labels.add(result); 165dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org return result; 166dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } 167dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org 168dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org /** 169dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org * Start defining instructions for the named label. 170dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org */ 171dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org public void mark(Label label) { 172dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org if (label.marked) { 173dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org throw new IllegalStateException("already marked"); 174dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } 175dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org label.marked = true; 176dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org if (currentLabel != null) { 177dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org jump(label); // blocks must end with a branch, return or throw 178dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } 179dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org currentLabel = label; 180dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } 181dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org 182dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org public void jump(Label target) { 183dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org addInstruction(new PlainInsn(Rops.GOTO, sourcePosition, null, RegisterSpecList.EMPTY), 184dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org target); 185dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } 186dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org 187dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org public void addCatchClause(Type<?> throwable, Label catchClause) { 188dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org if (catchTypes.contains(throwable)) { 189dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org throw new IllegalArgumentException("Already caught: " + throwable); 190dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } 191dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org catchTypes.add(throwable); 192dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org catches = toTypeList(catchTypes); 193dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org catchLabels.add(catchClause); 194dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } 195dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org 196dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org public Label removeCatchClause(Type<?> throwable) { 197dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org int index = catchTypes.indexOf(throwable); 198dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org if (index == -1) { 199dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org throw new IllegalArgumentException("No catch clause: " + throwable); 200dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } 201dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org catchTypes.remove(index); 202c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org catches = toTypeList(catchTypes); 203c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org return catchLabels.remove(index); 204c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org } 205c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org 206c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org public void throwValue(Local<?> throwable) { 207c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org addInstruction(new ThrowingInsn(Rops.THROW, sourcePosition, 208c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org RegisterSpecList.make(throwable.spec()), catches)); 209c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org } 210c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org 211e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org private StdTypeList toTypeList(List<Type<?>> types) { 212e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org StdTypeList result = new StdTypeList(types.size()); 213e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org for (int i = 0; i < types.size(); i++) { 214e900018c7a2a695fde788911564da37535c7e736mstarzinger@chromium.org result.set(i, types.get(i).ropType); 215dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } 216dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org return result; 217dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } 218dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org 219dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org private void addInstruction(Insn insn) { 220dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org addInstruction(insn, null); 221dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } 222dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org 223dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org /** 224dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org * @param branch the branches to follow; interpretation depends on the 225dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org * instruction's branchingness. 226dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org */ 227dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org private void addInstruction(Insn insn, Label branch) { 228dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org if (currentLabel == null || !currentLabel.marked) { 229dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org throw new IllegalStateException("no current label"); 230dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } 231dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org currentLabel.instructions.add(insn); 232dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org 233dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org switch (insn.getOpcode().getBranchingness()) { 234dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org case BRANCH_NONE: 235dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org if (branch != null) { 236dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org throw new IllegalArgumentException("unexpected branch: " + branch); 237dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } 238dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org return; 239dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org 240dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org case BRANCH_RETURN: 241dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org if (branch != null) { 242dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org throw new IllegalArgumentException("unexpected branch: " + branch); 243dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } 244dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org currentLabel = null; 245dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org break; 246dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org 247dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org case BRANCH_GOTO: 248dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org if (branch == null) { 249dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org throw new IllegalArgumentException("branch == null"); 250dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } 251dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org currentLabel.primarySuccessor = branch; 252dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org currentLabel = null; 253dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org break; 254dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org 255dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org case Rop.BRANCH_IF: 256dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org if (branch == null) { 257dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org throw new IllegalArgumentException("branch == null"); 258dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } 259dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org splitCurrentLabel(branch, Collections.<Label>emptyList()); 260dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org break; 261dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org 262dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org case Rop.BRANCH_THROW: 263dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org if (branch != null) { 264dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org throw new IllegalArgumentException("unexpected branch: " + branch); 265dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } 266dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org splitCurrentLabel(null, new ArrayList<Label>(catchLabels)); 267dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org break; 268dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org 269dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org default: 270dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org throw new IllegalArgumentException(); 271dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } 272dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } 273dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org 274dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org /** 275dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org * Closes the current label and starts a new one. 276dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org * 277dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org * @param catchLabels an immutable list of catch labels 278dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org */ 279dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org private void splitCurrentLabel(Label alternateSuccessor, List<Label> catchLabels) { 280dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org Label newLabel = newLabel(); 281dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org currentLabel.primarySuccessor = newLabel; 282dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org currentLabel.alternateSuccessor = alternateSuccessor; 283dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org currentLabel.catchLabels = catchLabels; 284dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org currentLabel = newLabel; 285dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org currentLabel.marked = true; 286dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } 287dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org 288dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org // instructions: constants 289dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org 290dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org public <T> void loadConstant(Local<T> target, T value) { 291dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org Rop rop = value == null 292dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org ? Rops.CONST_OBJECT_NOTHROW 293dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org : Rops.opConst(target.type.ropType); 294dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org if (rop.getBranchingness() == BRANCH_NONE) { 295dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org addInstruction(new PlainCstInsn(rop, sourcePosition, target.spec(), 296dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org RegisterSpecList.EMPTY, Constants.getConstant(value))); 297dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } else { 298ada3a6017e603965f87fa34f6e2fa60379e8d697machenbach@chromium.org addInstruction(new ThrowingCstInsn(rop, sourcePosition, 299dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org RegisterSpecList.EMPTY, catches, Constants.getConstant(value))); 300dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org moveResult(target, true); 301dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } 302dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } 303dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org 304dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org // instructions: unary 305dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org 306dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org public <T> void negate(Local<T> source, Local<T> target) { 307dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org unary(Rops.opNeg(source.type.ropType), source, target); 308dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } 309dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org 310dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org public <T> void not(Local<T> source, Local<T> target) { 311dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org unary(Rops.opNot(source.type.ropType), source, target); 312dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } 313d8a3a149cb9dac7437e264a2fe50f680418c3a45jkummerow@chromium.org 314d8a3a149cb9dac7437e264a2fe50f680418c3a45jkummerow@chromium.org public void numericCast(Local<?> source, Local<?> target) { 315d8a3a149cb9dac7437e264a2fe50f680418c3a45jkummerow@chromium.org unary(getCastRop(source.type.ropType, target.type.ropType), source, target); 316d8a3a149cb9dac7437e264a2fe50f680418c3a45jkummerow@chromium.org } 317dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org 318d0bddc653152f270a27fe32d5d7b0f5c0fa3b00cmachenbach@chromium.org private Rop getCastRop(com.android.dx.rop.type.Type sourceType, 319d0bddc653152f270a27fe32d5d7b0f5c0fa3b00cmachenbach@chromium.org com.android.dx.rop.type.Type targetType) { 320d0bddc653152f270a27fe32d5d7b0f5c0fa3b00cmachenbach@chromium.org if (sourceType.getBasicType() == BT_INT) { 321d0bddc653152f270a27fe32d5d7b0f5c0fa3b00cmachenbach@chromium.org switch (targetType.getBasicType()) { 322d0bddc653152f270a27fe32d5d7b0f5c0fa3b00cmachenbach@chromium.org case BT_SHORT: 323d0bddc653152f270a27fe32d5d7b0f5c0fa3b00cmachenbach@chromium.org return Rops.TO_SHORT; 324d0bddc653152f270a27fe32d5d7b0f5c0fa3b00cmachenbach@chromium.org case BT_CHAR: 325dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org return Rops.TO_CHAR; 326dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org case BT_BYTE: 327dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org return Rops.TO_BYTE; 328c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org } 329c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org } 330c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org return Rops.opConv(targetType, sourceType); 331c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org } 332c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org 333c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org private void unary(Rop rop, Local<?> source, Local<?> target) { 334c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org addInstruction(new PlainInsn(rop, sourcePosition, target.spec(), source.spec())); 335c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org } 336c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org 337dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org // instructions: binary 338dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org 339dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org public <T> void op(BinaryOp op, Local<T> target, Local<T> a, Local<T> b) { 340dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org Rop rop = op.rop(StdTypeList.make(a.type.ropType, b.type.ropType)); 341dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org RegisterSpecList sources = RegisterSpecList.make(a.spec(), b.spec()); 342dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org 343dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org if (rop.getBranchingness() == BRANCH_NONE) { 344dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org addInstruction(new PlainInsn(rop, sourcePosition, target.spec(), sources)); 345dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } else { 346dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org addInstruction(new ThrowingInsn(rop, sourcePosition, sources, catches)); 347dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org moveResult(target, true); 348dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } 349dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } 350dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org 351dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org // instructions: branches 352dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org 353dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org /** 354dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org * Compare ints. If the comparison is true, execution jumps to {@code 355dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org * trueLabel}. If it is false, execution continues to the next instruction. 356dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org */ 357dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org public <T> void compare(Comparison comparison, Local<T> a, Local<T> b, Label trueLabel) { 358dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org if (trueLabel == null) { 359dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org throw new IllegalArgumentException(); 360dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } 361dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org Rop rop = comparison.rop(StdTypeList.make(a.type.ropType, b.type.ropType)); 362dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org addInstruction(new PlainInsn(rop, sourcePosition, null, 363dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org RegisterSpecList.make(a.spec(), b.spec())), trueLabel); 364dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } 365dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org 366dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org /** 367dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org * Compare floats or doubles. 368dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org */ 369dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org public <T extends Number> void compare(Local<T> a, Local<T> b, Local<Integer> target, 370dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org int nanValue) { 371dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org Rop rop; 372dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org if (nanValue == 1) { 373dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org rop = Rops.opCmpg(a.type.ropType); 374dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } else if (nanValue == -1) { 375dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org rop = Rops.opCmpl(a.type.ropType); 376dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } else { 377dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org throw new IllegalArgumentException("expected 1 or -1 but was " + nanValue); 378dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } 379dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org addInstruction(new PlainInsn(rop, sourcePosition, target.spec(), 380dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org RegisterSpecList.make(a.spec(), b.spec()))); 381dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } 382dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org 383dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org /** 384dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org * Compare longs. 385dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org */ 386dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org public <T> void compare(Local<T> a, Local<T> b, Local<?> target) { 387dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org addInstruction(new PlainInsn(Rops.CMPL_LONG, sourcePosition, target.spec(), 388dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org RegisterSpecList.make(a.spec(), b.spec()))); 389dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } 390dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org 391dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org // instructions: fields 392dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org 393dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org public <D, V> void iget(FieldId<D, V> fieldId, Local<D> instance, Local<V> target) { 394dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org addInstruction(new ThrowingCstInsn(Rops.opGetField(target.type.ropType), sourcePosition, 395dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org RegisterSpecList.make(instance.spec()), catches, fieldId.constant)); 396dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org moveResult(target, true); 397dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org } 3985de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org 399dc94e19484d1700cb0ec22365444223e49a3ac1ejkummerow@chromium.org public <D, V> void iput(FieldId<D, V> fieldId, Local<D> instance, Local<V> source) { 4005de0074a922429f5e0ec2cf140c2d2989bf88140yangguo@chromium.org addInstruction(new ThrowingCstInsn(Rops.opPutField(source.type.ropType), sourcePosition, 401 RegisterSpecList.make(source.spec(), instance.spec()), catches, fieldId.constant)); 402 } 403 404 public <V> void sget(FieldId<?, V> fieldId, Local<V> target) { 405 addInstruction(new ThrowingCstInsn(Rops.opGetStatic(target.type.ropType), sourcePosition, 406 RegisterSpecList.EMPTY, catches, fieldId.constant)); 407 moveResult(target, true); 408 } 409 410 public <V> void sput(FieldId<?, V> fieldId, Local<V> source) { 411 addInstruction(new ThrowingCstInsn(Rops.opPutStatic(source.type.ropType), sourcePosition, 412 RegisterSpecList.make(source.spec()), catches, fieldId.constant)); 413 } 414 415 // instructions: invoke 416 417 public <T> void newInstance(Local<T> target, MethodId<T, Void> constructor, Local<?>... args) { 418 if (target == null) { 419 throw new IllegalArgumentException(); 420 } 421 addInstruction(new ThrowingCstInsn(Rops.NEW_INSTANCE, sourcePosition, 422 RegisterSpecList.EMPTY, catches, constructor.declaringType.constant)); 423 moveResult(target, true); 424 invokeDirect(constructor, null, target, args); 425 } 426 427 public <R> void invokeStatic(MethodId<?, R> method, Local<? super R> target, Local<?>... args) { 428 invoke(Rops.opInvokeStatic(method.prototype(true)), method, target, null, args); 429 } 430 431 public <D, R> void invokeVirtual(MethodId<D, R> method, Local<? super R> target, 432 Local<? extends D> object, Local<?>... args) { 433 invoke(Rops.opInvokeVirtual(method.prototype(true)), method, target, object, args); 434 } 435 436 public <D, R> void invokeDirect(MethodId<D, R> method, Local<? super R> target, 437 Local<? extends D> object, Local<?>... args) { 438 invoke(Rops.opInvokeDirect(method.prototype(true)), method, target, object, args); 439 } 440 441 public <D, R> void invokeSuper(MethodId<D, R> method, Local<? super R> target, 442 Local<? extends D> object, Local<?>... args) { 443 invoke(Rops.opInvokeSuper(method.prototype(true)), method, target, object, args); 444 } 445 446 public <D, R> void invokeInterface(MethodId<D, R> method, Local<? super R> target, 447 Local<? extends D> object, Local<?>... args) { 448 invoke(Rops.opInvokeInterface(method.prototype(true)), method, target, object, args); 449 } 450 451 private <D, R> void invoke(Rop rop, MethodId<D, R> method, Local<? super R> target, 452 Local<? extends D> object, Local<?>... args) { 453 addInstruction(new ThrowingCstInsn(rop, sourcePosition, concatenate(object, args), 454 catches, method.constant)); 455 if (target != null) { 456 moveResult(target, false); 457 } 458 } 459 460 // instructions: types 461 462 public void instanceOfType(Local<?> target, Local<?> source, Type<?> type) { 463 addInstruction(new ThrowingCstInsn(Rops.INSTANCE_OF, sourcePosition, 464 RegisterSpecList.make(source.spec()), catches, type.constant)); 465 moveResult(target, true); 466 } 467 468 public void typeCast(Local<?> source, Local<?> target) { 469 addInstruction(new ThrowingCstInsn(Rops.CHECK_CAST, sourcePosition, 470 RegisterSpecList.make(source.spec()), catches, target.type.constant)); 471 moveResult(target, true); 472 } 473 474 // instructions: arrays 475 476 public <T> void arrayLength(Local<T> array, Local<Integer> target) { 477 addInstruction(new ThrowingInsn(Rops.ARRAY_LENGTH, sourcePosition, 478 RegisterSpecList.make(array.spec()), catches)); 479 moveResult(target, true); 480 } 481 482 public <T> void newArray(Local<Integer> length, Local<T> target) { 483 addInstruction(new ThrowingCstInsn(Rops.opNewArray(target.type.ropType), sourcePosition, 484 RegisterSpecList.make(length.spec()), catches, target.type.constant)); 485 moveResult(target, true); 486 } 487 488 public void aget(Local<?> array, Local<Integer> index, Local<?> target) { 489 addInstruction(new ThrowingInsn(Rops.opAget(target.type.ropType), sourcePosition, 490 RegisterSpecList.make(array.spec(), index.spec()), catches)); 491 moveResult(target, true); 492 } 493 494 public void aput(Local<?> array, Local<Integer> index, Local<?> source) { 495 addInstruction(new ThrowingInsn(Rops.opAput(source.type.ropType), sourcePosition, 496 RegisterSpecList.make(source.spec(), array.spec(), index.spec()), catches)); 497 } 498 499 // instructions: return 500 501 public void returnVoid() { 502 if (!method.returnType.equals(Type.VOID)) { 503 throw new IllegalArgumentException("declared " + method.returnType 504 + " but returned void"); 505 } 506 addInstruction(new PlainInsn(Rops.RETURN_VOID, sourcePosition, null, 507 RegisterSpecList.EMPTY)); 508 } 509 510 public void returnValue(Local<?> result) { 511 if (!result.type.equals(method.returnType)) { 512 // TODO: this is probably too strict. 513 throw new IllegalArgumentException("declared " + method.returnType 514 + " but returned " + result.type); 515 } 516 addInstruction(new PlainInsn(Rops.opReturn(result.type.ropType), sourcePosition, 517 null, RegisterSpecList.make(result.spec()))); 518 } 519 520 private void moveResult(Local<?> target, boolean afterNonInvokeThrowingInsn) { 521 Rop rop = afterNonInvokeThrowingInsn 522 ? Rops.opMoveResultPseudo(target.type.ropType) 523 : Rops.opMoveResult(target.type.ropType); 524 addInstruction(new PlainInsn(rop, sourcePosition, target.spec(), RegisterSpecList.EMPTY)); 525 } 526 527 // produce BasicBlocks for dex 528 529 BasicBlockList toBasicBlocks() { 530 if (!localsInitialized) { 531 initializeLocals(); 532 } 533 534 cleanUpLabels(); 535 536 BasicBlockList result = new BasicBlockList(labels.size()); 537 for (int i = 0; i < labels.size(); i++) { 538 result.set(i, labels.get(i).toBasicBlock()); 539 } 540 return result; 541 } 542 543 /** 544 * Removes empty labels and assigns IDs to non-empty labels. 545 */ 546 private void cleanUpLabels() { 547 int id = 0; 548 for (Iterator<Label> i = labels.iterator(); i.hasNext();) { 549 Label label = i.next(); 550 if (label.isEmpty()) { 551 i.remove(); 552 } else { 553 label.compact(); 554 label.id = id++; 555 } 556 } 557 } 558 559 private static RegisterSpecList concatenate(Local<?> first, Local<?>[] rest) { 560 int offset = (first != null) ? 1 : 0; 561 RegisterSpecList result = new RegisterSpecList(offset + rest.length); 562 if (first != null) { 563 result.set(0, first.spec()); 564 } 565 for (int i = 0; i < rest.length; i++) { 566 result.set(i + offset, rest[i].spec()); 567 } 568 return result; 569 } 570} 571