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 17 package com.android.dx.rop.code; 18 19 import com.android.dx.rop.type.TypeList; 20 import com.android.dx.util.Hex; 21 import com.android.dx.util.IntList; 22 import com.android.dx.util.LabeledItem; 23 24 /** 25 * Basic block of register-based instructions. 26 */ 27 public final class BasicBlock implements LabeledItem { 28 /** {@code >= 0;} target label for this block */ 29 private final int label; 30 31 /** {@code non-null;} list of instructions in this block */ 32 private final InsnList insns; 33 34 /** 35 * {@code non-null;} full list of successors that this block may 36 * branch to 37 */ 38 private final IntList successors; 39 40 /** 41 * {@code >= -1;} the primary / standard-flow / "default" successor, or 42 * {@code -1} if this block has no successors (that is, it 43 * exits the function/method) 44 */ 45 private final int primarySuccessor; 46 47 /** 48 * Constructs an instance. The predecessor set is set to {@code null}. 49 * 50 * @param label {@code >= 0;} target label for this block 51 * @param insns {@code non-null;} list of instructions in this block 52 * @param successors {@code non-null;} full list of successors that this 53 * block may branch to 54 * @param primarySuccessor {@code >= -1;} the primary / standard-flow / 55 * "default" successor, or {@code -1} if this block has no 56 * successors (that is, it exits the function/method or is an 57 * unconditional throw) 58 */ BasicBlock(int label, InsnList insns, IntList successors, int primarySuccessor)59 public BasicBlock(int label, InsnList insns, IntList successors, 60 int primarySuccessor) { 61 if (label < 0) { 62 throw new IllegalArgumentException("label < 0"); 63 } 64 65 try { 66 insns.throwIfMutable(); 67 } catch (NullPointerException ex) { 68 // Elucidate exception. 69 throw new NullPointerException("insns == null"); 70 } 71 72 int sz = insns.size(); 73 74 if (sz == 0) { 75 throw new IllegalArgumentException("insns.size() == 0"); 76 } 77 78 for (int i = sz - 2; i >= 0; i--) { 79 Rop one = insns.get(i).getOpcode(); 80 if (one.getBranchingness() != Rop.BRANCH_NONE) { 81 throw new IllegalArgumentException("insns[" + i + "] is a " + 82 "branch or can throw"); 83 } 84 } 85 86 Insn lastInsn = insns.get(sz - 1); 87 if (lastInsn.getOpcode().getBranchingness() == Rop.BRANCH_NONE) { 88 throw new IllegalArgumentException("insns does not end with " + 89 "a branch or throwing " + 90 "instruction"); 91 } 92 93 try { 94 successors.throwIfMutable(); 95 } catch (NullPointerException ex) { 96 // Elucidate exception. 97 throw new NullPointerException("successors == null"); 98 } 99 100 if (primarySuccessor < -1) { 101 throw new IllegalArgumentException("primarySuccessor < -1"); 102 } 103 104 if (primarySuccessor >= 0 && !successors.contains(primarySuccessor)) { 105 throw new IllegalArgumentException( 106 "primarySuccessor " + primarySuccessor + " not in successors " + successors); 107 } 108 109 this.label = label; 110 this.insns = insns; 111 this.successors = successors; 112 this.primarySuccessor = primarySuccessor; 113 } 114 115 /** 116 * {@inheritDoc} 117 * 118 * Instances of this class compare by identity. That is, 119 * {@code x.equals(y)} is only true if {@code x == y}. 120 */ 121 @Override equals(Object other)122 public boolean equals(Object other) { 123 return (this == other); 124 } 125 126 /** 127 * {@inheritDoc} 128 * 129 * Return the identity hashcode of this instance. This is proper, 130 * since instances of this class compare by identity (see {@link #equals}). 131 */ 132 @Override hashCode()133 public int hashCode() { 134 return System.identityHashCode(this); 135 } 136 137 /** 138 * Gets the target label of this block. 139 * 140 * @return {@code >= 0;} the label 141 */ getLabel()142 public int getLabel() { 143 return label; 144 } 145 146 /** 147 * Gets the list of instructions inside this block. 148 * 149 * @return {@code non-null;} the instruction list 150 */ getInsns()151 public InsnList getInsns() { 152 return insns; 153 } 154 155 /** 156 * Gets the list of successors that this block may branch to. 157 * 158 * @return {@code non-null;} the successors list 159 */ getSuccessors()160 public IntList getSuccessors() { 161 return successors; 162 } 163 164 /** 165 * Gets the primary successor of this block. 166 * 167 * @return {@code >= -1;} the primary successor, or {@code -1} if this 168 * block has no successors at all 169 */ getPrimarySuccessor()170 public int getPrimarySuccessor() { 171 return primarySuccessor; 172 } 173 174 /** 175 * Gets the secondary successor of this block. It is only valid to call 176 * this method on blocks that have exactly two successors. 177 * 178 * @return {@code >= 0;} the secondary successor 179 */ getSecondarySuccessor()180 public int getSecondarySuccessor() { 181 if (successors.size() != 2) { 182 throw new UnsupportedOperationException( 183 "block doesn't have exactly two successors"); 184 } 185 186 int succ = successors.get(0); 187 if (succ == primarySuccessor) { 188 succ = successors.get(1); 189 } 190 191 return succ; 192 } 193 194 /** 195 * Gets the first instruction of this block. This is just a 196 * convenient shorthand for {@code getInsns().get(0)}. 197 * 198 * @return {@code non-null;} the first instruction 199 */ getFirstInsn()200 public Insn getFirstInsn() { 201 return insns.get(0); 202 } 203 204 /** 205 * Gets the last instruction of this block. This is just a 206 * convenient shorthand for {@code getInsns().getLast()}. 207 * 208 * @return {@code non-null;} the last instruction 209 */ getLastInsn()210 public Insn getLastInsn() { 211 return insns.getLast(); 212 } 213 214 /** 215 * Returns whether this block might throw an exception. This is 216 * just a convenient shorthand for {@code getLastInsn().canThrow()}. 217 * 218 * @return {@code true} iff this block might throw an 219 * exception 220 */ canThrow()221 public boolean canThrow() { 222 return insns.getLast().canThrow(); 223 } 224 225 /** 226 * Returns whether this block has any associated exception handlers. 227 * This is just a shorthand for inspecting the last instruction in 228 * the block to see if it could throw, and if so, whether it in fact 229 * has any associated handlers. 230 * 231 * @return {@code true} iff this block has any associated 232 * exception handlers 233 */ hasExceptionHandlers()234 public boolean hasExceptionHandlers() { 235 Insn lastInsn = insns.getLast(); 236 return lastInsn.getCatches().size() != 0; 237 } 238 239 /** 240 * Returns the exception handler types associated with this block, 241 * if any. This is just a shorthand for inspecting the last 242 * instruction in the block to see if it could throw, and if so, 243 * grabbing the catch list out of it. If not, this returns an 244 * empty list (not {@code null}). 245 * 246 * @return {@code non-null;} the exception handler types associated with 247 * this block 248 */ getExceptionHandlerTypes()249 public TypeList getExceptionHandlerTypes() { 250 Insn lastInsn = insns.getLast(); 251 return lastInsn.getCatches(); 252 } 253 254 /** 255 * Returns an instance that is identical to this one, except that 256 * the registers in each instruction are offset by the given 257 * amount. 258 * 259 * @param delta the amount to offset register numbers by 260 * @return {@code non-null;} an appropriately-constructed instance 261 */ withRegisterOffset(int delta)262 public BasicBlock withRegisterOffset(int delta) { 263 return new BasicBlock(label, insns.withRegisterOffset(delta), 264 successors, primarySuccessor); 265 } 266 toString()267 public String toString() { 268 return '{' + Hex.u2(label) + '}'; 269 } 270 271 /** 272 * BasicBlock visitor interface 273 */ 274 public interface Visitor { 275 /** 276 * Visits a basic block 277 * @param b block visited 278 */ visitBlock(BasicBlock b)279 public void visitBlock (BasicBlock b); 280 } 281 } 282