1/* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.dx.dex.code; 18 19import com.android.dx.rop.code.RegisterSpecList; 20import com.android.dx.rop.code.SourcePosition; 21 22/** 23 * Instruction which has a single branch target. 24 */ 25public final class TargetInsn extends FixedSizeInsn { 26 /** {@code non-null;} the branch target */ 27 private CodeAddress target; 28 29 /** 30 * Constructs an instance. The output address of this instance is initially 31 * unknown ({@code -1}), and the target is initially 32 * {@code null}. 33 * 34 * @param opcode the opcode; one of the constants from {@link Dops} 35 * @param position {@code non-null;} source position 36 * @param registers {@code non-null;} register list, including a 37 * result register if appropriate (that is, registers may be either 38 * ins or outs) 39 * @param target {@code non-null;} the branch target 40 */ 41 public TargetInsn(Dop opcode, SourcePosition position, 42 RegisterSpecList registers, CodeAddress target) { 43 super(opcode, position, registers); 44 45 if (target == null) { 46 throw new NullPointerException("target == null"); 47 } 48 49 this.target = target; 50 } 51 52 /** {@inheritDoc} */ 53 @Override 54 public DalvInsn withOpcode(Dop opcode) { 55 return new TargetInsn(opcode, getPosition(), getRegisters(), target); 56 } 57 58 /** {@inheritDoc} */ 59 @Override 60 public DalvInsn withRegisters(RegisterSpecList registers) { 61 return new TargetInsn(getOpcode(), getPosition(), registers, target); 62 } 63 64 /** 65 * Returns an instance that is just like this one, except that its 66 * opcode has the opposite sense (as a test; e.g. a 67 * {@code lt} test becomes a {@code ge}), and its branch 68 * target is replaced by the one given, and all set-once values 69 * associated with the class (such as its address) are reset. 70 * 71 * @param target {@code non-null;} the new branch target 72 * @return {@code non-null;} an appropriately-constructed instance 73 */ 74 public TargetInsn withNewTargetAndReversed(CodeAddress target) { 75 Dop opcode = getOpcode().getOppositeTest(); 76 77 return new TargetInsn(opcode, getPosition(), getRegisters(), target); 78 } 79 80 /** 81 * Gets the unique branch target of this instruction. 82 * 83 * @return {@code non-null;} the branch target 84 */ 85 public CodeAddress getTarget() { 86 return target; 87 } 88 89 /** 90 * Gets the target address of this instruction. This is only valid 91 * to call if the target instruction has been assigned an address, 92 * and it is merely a convenient shorthand for 93 * {@code getTarget().getAddress()}. 94 * 95 * @return {@code >= 0;} the target address 96 */ 97 public int getTargetAddress() { 98 return target.getAddress(); 99 } 100 101 /** 102 * Gets the branch offset of this instruction. This is only valid to 103 * call if both this and the target instruction each has been assigned 104 * an address, and it is merely a convenient shorthand for 105 * {@code getTargetAddress() - getAddress()}. 106 * 107 * @return the branch offset 108 */ 109 public int getTargetOffset() { 110 return target.getAddress() - getAddress(); 111 } 112 113 /** 114 * Returns whether the target offset is known. 115 * 116 * @return {@code true} if the target offset is known or 117 * {@code false} if not 118 */ 119 public boolean hasTargetOffset() { 120 return hasAddress() && target.hasAddress(); 121 } 122 123 /** {@inheritDoc} */ 124 @Override 125 protected String argString() { 126 if (target == null) { 127 return "????"; 128 } 129 130 return target.identifierString(); 131 } 132} 133