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