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.ssa; 18 19import com.android.dx.rop.code.*; 20import com.android.dx.util.ToHuman; 21 22/** 23 * An instruction in SSA form 24 */ 25public abstract class SsaInsn implements ToHuman, Cloneable { 26 /** {@code non-null;} the block that contains this instance */ 27 private final SsaBasicBlock block; 28 29 /** {@code null-ok;} result register */ 30 private RegisterSpec result; 31 32 /** 33 * Constructs an instance. 34 * 35 * @param result {@code null-ok;} initial result register. May be changed. 36 * @param block {@code non-null;} block containing this insn. Can 37 * never change. 38 */ 39 protected SsaInsn(RegisterSpec result, SsaBasicBlock block) { 40 if (block == null) { 41 throw new NullPointerException("block == null"); 42 } 43 44 this.block = block; 45 this.result = result; 46 } 47 48 /** 49 * Makes a new SSA insn form a rop insn. 50 * 51 * @param insn {@code non-null;} rop insn 52 * @param block {@code non-null;} owning block 53 * @return {@code non-null;} an appropriately constructed instance 54 */ 55 public static SsaInsn makeFromRop(Insn insn, SsaBasicBlock block) { 56 return new NormalSsaInsn(insn, block); 57 } 58 59 /** {@inheritDoc} */ 60 @Override 61 public SsaInsn clone() { 62 try { 63 return (SsaInsn)super.clone(); 64 } catch (CloneNotSupportedException ex) { 65 throw new RuntimeException ("unexpected", ex); 66 } 67 } 68 69 /** 70 * Like {@link com.android.dx.rop.code.Insn getResult()}. 71 * 72 * @return result register 73 */ 74 public RegisterSpec getResult() { 75 return result; 76 } 77 78 /** 79 * Set the result register. 80 * 81 * @param result {@code non-null;} the new result register 82 */ 83 protected void setResult(RegisterSpec result) { 84 if (result == null) { 85 throw new NullPointerException("result == null"); 86 } 87 88 this.result = result; 89 } 90 91 /** 92 * Like {@link com.android.dx.rop.code.Insn getSources()}. 93 * 94 * @return {@code non-null;} sources list 95 */ 96 abstract public RegisterSpecList getSources(); 97 98 /** 99 * Gets the block to which this insn instance belongs. 100 * 101 * @return owning block 102 */ 103 public SsaBasicBlock getBlock() { 104 return block; 105 } 106 107 /** 108 * Returns whether or not the specified reg is the result reg. 109 * 110 * @param reg register to test 111 * @return true if there is a result and it is stored in the specified 112 * register 113 */ 114 public boolean isResultReg(int reg) { 115 return result != null && result.getReg() == reg; 116 } 117 118 119 /** 120 * Changes the result register if this insn has a result. This is used 121 * during renaming. 122 * 123 * @param reg new result register 124 */ 125 public void changeResultReg(int reg) { 126 if (result != null) { 127 result = result.withReg(reg); 128 } 129 } 130 131 /** 132 * Sets the local association for the result of this insn. This is 133 * sometimes updated during the SsaRenamer process. 134 * 135 * @param local {@code null-ok;} new debug/local variable info 136 */ 137 public final void setResultLocal(LocalItem local) { 138 LocalItem oldItem = result.getLocalItem(); 139 140 if (local != oldItem && (local == null 141 || !local.equals(result.getLocalItem()))) { 142 result = RegisterSpec.makeLocalOptional( 143 result.getReg(), result.getType(), local); 144 } 145 } 146 147 /** 148 * Map registers after register allocation. 149 * 150 * @param mapper {@code non-null;} mapping from old to new registers 151 */ 152 public final void mapRegisters(RegisterMapper mapper) { 153 RegisterSpec oldResult = result; 154 155 result = mapper.map(result); 156 block.getParent().updateOneDefinition(this, oldResult); 157 mapSourceRegisters(mapper); 158 } 159 160 /** 161 * Maps only source registers. 162 * 163 * @param mapper new mapping 164 */ 165 abstract public void mapSourceRegisters(RegisterMapper mapper); 166 167 /** 168 * Returns the Rop opcode for this insn, or null if this is a phi insn. 169 * 170 * TODO: Move this up into NormalSsaInsn. 171 * 172 * @return {@code null-ok;} Rop opcode if there is one. 173 */ 174 abstract public Rop getOpcode(); 175 176 /** 177 * Returns the original Rop insn for this insn, or null if this is 178 * a phi insn. 179 * 180 * TODO: Move this up into NormalSsaInsn. 181 * 182 * @return {@code null-ok;} Rop insn if there is one. 183 */ 184 abstract public Insn getOriginalRopInsn(); 185 186 /** 187 * Gets the spec of a local variable assignment that occurs at this 188 * instruction, or null if no local variable assignment occurs. This 189 * may be the result register, or for {@code mark-local} insns 190 * it may be the source. 191 * 192 * @see com.android.dx.rop.code.Insn#getLocalAssignment() 193 * 194 * @return {@code null-ok;} a local-associated register spec or null 195 */ 196 public RegisterSpec getLocalAssignment() { 197 if (result != null && result.getLocalItem() != null) { 198 return result; 199 } 200 201 return null; 202 } 203 204 /** 205 * Indicates whether the specified register is amongst the registers 206 * used as sources for this instruction. 207 * 208 * @param reg the register in question 209 * @return true if the reg is a source 210 */ 211 public boolean isRegASource(int reg) { 212 return null != getSources().specForRegister(reg); 213 } 214 215 /** 216 * Transform back to ROP form. 217 * 218 * TODO: Move this up into NormalSsaInsn. 219 * 220 * @return {@code non-null;} a ROP representation of this instruction, with 221 * updated registers. 222 */ 223 public abstract Insn toRopInsn(); 224 225 /** 226 * @return true if this is a PhiInsn or a normal move insn 227 */ 228 public abstract boolean isPhiOrMove(); 229 230 /** 231 * Returns true if this insn is considered to have a side effect beyond 232 * that of assigning to the result reg. 233 * 234 * @return true if this insn is considered to have a side effect beyond 235 * that of assigning to the result reg. 236 */ 237 public abstract boolean hasSideEffect(); 238 239 /** 240 * @return true if this is a move (but not a move-operand or 241 * move-exception) instruction 242 */ 243 public boolean isNormalMoveInsn() { 244 return false; 245 } 246 247 /** 248 * @return true if this is a move-exception instruction. 249 * These instructions must immediately follow a preceeding invoke* 250 */ 251 public boolean isMoveException() { 252 return false; 253 } 254 255 /** 256 * @return true if this instruction can throw. 257 */ 258 abstract public boolean canThrow(); 259 260 /** 261 * Accepts a visitor. 262 * 263 * @param v {@code non-null} the visitor 264 */ 265 public abstract void accept(Visitor v); 266 267 /** 268 * Visitor interface for this class. 269 */ 270 public static interface Visitor { 271 /** 272 * Any non-phi move instruction 273 * @param insn {@code non-null;} the instruction to visit 274 */ 275 public void visitMoveInsn(NormalSsaInsn insn); 276 277 /** 278 * Any phi insn 279 * @param insn {@code non-null;} the instruction to visit 280 */ 281 public void visitPhiInsn(PhiInsn insn); 282 283 /** 284 * Any insn that isn't a move or a phi (which is also a move). 285 * @param insn {@code non-null;} the instruction to visit 286 */ 287 public void visitNonMoveInsn(NormalSsaInsn insn); 288 } 289} 290