/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.dexmaker; import com.android.dx.rop.code.BasicBlockList; import com.android.dx.rop.code.Insn; import com.android.dx.rop.code.PlainCstInsn; import com.android.dx.rop.code.PlainInsn; import com.android.dx.rop.code.RegisterSpecList; import com.android.dx.rop.code.Rop; import static com.android.dx.rop.code.Rop.BRANCH_GOTO; import static com.android.dx.rop.code.Rop.BRANCH_NONE; import static com.android.dx.rop.code.Rop.BRANCH_RETURN; import com.android.dx.rop.code.Rops; import com.android.dx.rop.code.SourcePosition; import com.android.dx.rop.code.ThrowingCstInsn; import com.android.dx.rop.code.ThrowingInsn; import com.android.dx.rop.cst.CstInteger; import com.android.dx.rop.type.StdTypeList; import static com.android.dx.rop.type.Type.BT_BYTE; import static com.android.dx.rop.type.Type.BT_CHAR; import static com.android.dx.rop.type.Type.BT_INT; import static com.android.dx.rop.type.Type.BT_SHORT; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; /** * Builds a sequence of instructions. * *

Locals

* All data manipulation takes place in local variables. Each parameter gets its * own local by default; access these using {@link #getParameter * getParameter()}. Non-static methods and constructors also have a {@code this} * parameter; it's available as {@link #getThis getThis()}. Allocate a new local * variable using {@link #newLocal newLocal()}, and assign a default value to it * with {@link #loadConstant loadConstant()}. Copy a value from one local to * another with {@link #move move()}. * *

Every local variable has a fixed type. This is either a primitive type (of * any size) or a reference type. This class emits instructions appropriate to * the types they operate on. Not all operations are local on all types; * attempting to emit such an operation will fail with an unchecked exception. * *

Math and Bit Operations

* Transform a single value into another related value using {@link * #op(UnaryOp,Local,Local) op(UnaryOp, Local, Local)}. Transform two values * into a third value using {@link #op(BinaryOp,Local,Local,Local) op(BinaryOp, * Local, Local, Local)}. In either overload the first {@code Local} parameter * is where the result will be sent; the other {@code Local} parameters are the * inputs. * *

Comparisons

* There are three different comparison operations each with different * constraints: * * There's no single operation to compare longs and jump, or to compare ints and * store the result in a local. Accomplish these goals by chaining multiple * operations together. * *

Branches, Labels and Returns

* Basic control flow is expressed using jumps and labels. Each label must be * marked exactly once and may be jumped to any number of times. Create a label * using its constructor: {@code new Label()}, and mark it using {@link #mark * mark(Label)}. All jumps to a label will execute instructions starting from * that label. You can jump to a label that hasn't yet been marked (jumping * forward) or to a label that has already been marked (jumping backward). Jump * unconditionally with {@link #jump jump(Label)} or conditionally based on a * comparison using {@link #compare compare()}. * *

Most methods should contain either a return instruction. Void methods * should use {@link #returnVoid()}; non-void methods should use {@link * #returnValue returnValue()} with a local whose return type matches the * method's return type. Constructors are considered void methods and should * call {@link #returnVoid()}. Methods may make multiple returns. Methods * containing no return statements must either loop infinitely or throw * unconditionally; it is not legal to end a sequence of instructions without a * jump, return or throw. * *

Throwing and Catching

* This API uses labels to handle thrown exceptions, errors and throwables. Call * {@link #addCatchClause addCatchClause()} to register the target label and * throwable class. All statements that follow will jump to that catch clause if * they throw a {@link Throwable} assignable to that type. Use {@link * #removeCatchClause removeCatchClause()} to unregister the throwable class. * *

Throw an throwable by first assigning it to a local and then calling * {@link #throwValue throwValue()}. Control flow will jump to the nearest label * assigned to a type assignable to the thrown type. In this context, "nearest" * means the label requiring the fewest stack frames to be popped. * *

Calling methods

* A method's caller must know its return type, name, parameters, and invoke * kind. Lookup a method on a type using {@link TypeId#getMethod * TypeId.getMethod()}. This is more onerous than Java language invokes, which * can infer the target method using the target object and parameters. There are * four invoke kinds: * * All invoke methods take a local for the return value. For void methods this * local is unused and may be null. * *

Field Access

* Read static fields using {@link #sget sget()}; write them using {@link * #sput sput()}. For instance values you'll need to specify the declaring * instance; use {@link #getThis getThis()} in an instance method to use {@code * this}. Read instance values using {@link #iget iget()} and write them with * {@link #iput iput()}. * *

Array Access

* Allocate an array using {@link #newArray newArray()}. Read an array's length * with {@link #arrayLength arrayLength()} and its elements with {@link #aget * aget()}. Write an array's elements with {@link #aput aput()}. * *

Types

* Use {@link #cast cast()} to perform either a numeric cast or * a type cast. Interrogate the type of a value in a local * using {@link #instanceOfType instanceOfType()}. * *

Synchronization

* Acquire a monitor using {@link #monitorEnter monitorEnter()}; release it with * {@link #monitorExit monitorExit()}. It is the caller's responsibility to * guarantee that enter and exit calls are balanced, even in the presence of * exceptions thrown. * * Warning: Even if a method has the {@code synchronized} flag, * dex requires instructions to acquire and release monitors manually. A method * declared with {@link java.lang.reflect.Modifier#SYNCHRONIZED SYNCHRONIZED} * but without manual calls to {@code monitorEnter()} and {@code monitorExit()} * will not be synchronized when executed. */ public final class Code { private final MethodId method; /** * All allocated labels. Although the order of the labels in this list * shouldn't impact behavior, it is used to determine basic block indices. */ private final List