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.RegOps; 22 import com.android.dx.rop.code.RegisterSpec; 23 import com.android.dx.rop.code.RegisterSpecList; 24 import com.android.dx.rop.code.Rop; 25 26 /** 27 * A "normal" (non-phi) instruction in SSA form. Always wraps a rop insn. 28 */ 29 public final class NormalSsaInsn extends SsaInsn implements Cloneable { 30 /** {@code non-null;} rop insn that we're wrapping */ 31 private Insn insn; 32 33 /** 34 * Creates an instance. 35 * 36 * @param insn Rop insn to wrap 37 * @param block block that contains this insn 38 */ NormalSsaInsn(final Insn insn, final SsaBasicBlock block)39 NormalSsaInsn(final Insn insn, final SsaBasicBlock block) { 40 super(insn.getResult(), block); 41 this.insn = insn; 42 } 43 44 /** {@inheritDoc} */ 45 @Override mapSourceRegisters(RegisterMapper mapper)46 public final void mapSourceRegisters(RegisterMapper mapper) { 47 RegisterSpecList oldSources = insn.getSources(); 48 RegisterSpecList newSources = mapper.map(oldSources); 49 50 if (newSources != oldSources) { 51 insn = insn.withNewRegisters(getResult(), newSources); 52 getBlock().getParent().onSourcesChanged(this, oldSources); 53 } 54 } 55 56 /** 57 * Changes one of the insn's sources. New source should be of same type 58 * and category. 59 * 60 * @param index {@code >=0;} index of source to change 61 * @param newSpec spec for new source 62 */ changeOneSource(int index, RegisterSpec newSpec)63 public final void changeOneSource(int index, RegisterSpec newSpec) { 64 RegisterSpecList origSources = insn.getSources(); 65 int sz = origSources.size(); 66 RegisterSpecList newSources = new RegisterSpecList(sz); 67 68 for (int i = 0; i < sz; i++) { 69 newSources.set(i, i == index ? newSpec : origSources.get(i)); 70 } 71 72 newSources.setImmutable(); 73 74 RegisterSpec origSpec = origSources.get(index); 75 if (origSpec.getReg() != newSpec.getReg()) { 76 /* 77 * If the register remains unchanged, we're only changing 78 * the type or local var name so don't update use list 79 */ 80 getBlock().getParent().onSourceChanged(this, origSpec, newSpec); 81 } 82 83 insn = insn.withNewRegisters(getResult(), newSources); 84 } 85 86 /** 87 * Changes the source list of the insn. New source list should be the 88 * same size and consist of sources of identical types. 89 * 90 * @param newSources non-null new sources list. 91 */ setNewSources(RegisterSpecList newSources)92 public final void setNewSources (RegisterSpecList newSources) { 93 RegisterSpecList origSources = insn.getSources(); 94 95 if (origSources.size() != newSources.size()) { 96 throw new RuntimeException("Sources counts don't match"); 97 } 98 99 insn = insn.withNewRegisters(getResult(), newSources); 100 } 101 102 /** {@inheritDoc} */ 103 @Override clone()104 public NormalSsaInsn clone() { 105 return (NormalSsaInsn) super.clone(); 106 } 107 108 /** 109 * Like rop.Insn.getSources(). 110 * 111 * @return {@code null-ok;} sources list 112 */ 113 @Override getSources()114 public RegisterSpecList getSources() { 115 return insn.getSources(); 116 } 117 118 /** {@inheritDoc} */ toHuman()119 public String toHuman() { 120 return toRopInsn().toHuman(); 121 } 122 123 /** {@inheritDoc} */ 124 @Override toRopInsn()125 public Insn toRopInsn() { 126 return insn.withNewRegisters(getResult(), insn.getSources()); 127 } 128 129 /** 130 * @return the Rop opcode for this insn 131 */ 132 @Override getOpcode()133 public Rop getOpcode() { 134 return insn.getOpcode(); 135 } 136 137 /** {@inheritDoc} */ 138 @Override getOriginalRopInsn()139 public Insn getOriginalRopInsn() { 140 return insn; 141 } 142 143 /** {@inheritDoc} */ 144 @Override getLocalAssignment()145 public RegisterSpec getLocalAssignment() { 146 RegisterSpec assignment; 147 148 if (insn.getOpcode().getOpcode() == RegOps.MARK_LOCAL) { 149 assignment = insn.getSources().get(0); 150 } else { 151 assignment = getResult(); 152 } 153 154 if (assignment == null) { 155 return null; 156 } 157 158 LocalItem local = assignment.getLocalItem(); 159 160 if (local == null) { 161 return null; 162 } 163 164 return assignment; 165 } 166 167 /** 168 * Upgrades this insn to a version that represents the constant source 169 * literally. If the upgrade is not possible, this does nothing. 170 * 171 * @see Insn#withSourceLiteral 172 */ upgradeToLiteral()173 public void upgradeToLiteral() { 174 RegisterSpecList oldSources = insn.getSources(); 175 176 insn = insn.withSourceLiteral(); 177 getBlock().getParent().onSourcesChanged(this, oldSources); 178 } 179 180 /** 181 * @return true if this is a move (but not a move-operand) instruction 182 */ 183 @Override isNormalMoveInsn()184 public boolean isNormalMoveInsn() { 185 return insn.getOpcode().getOpcode() == RegOps.MOVE; 186 } 187 188 /** {@inheritDoc} */ 189 @Override isMoveException()190 public boolean isMoveException() { 191 return insn.getOpcode().getOpcode() == RegOps.MOVE_EXCEPTION; 192 } 193 194 /** {@inheritDoc} */ 195 @Override canThrow()196 public boolean canThrow() { 197 return insn.canThrow(); 198 } 199 200 /** {@inheritDoc} */ 201 @Override accept(Visitor v)202 public void accept(Visitor v) { 203 if (isNormalMoveInsn()) { 204 v.visitMoveInsn(this); 205 } else { 206 v.visitNonMoveInsn(this); 207 } 208 } 209 210 /** {@inheritDoc} */ 211 @Override isPhiOrMove()212 public boolean isPhiOrMove() { 213 return isNormalMoveInsn(); 214 } 215 216 /** 217 * {@inheritDoc} 218 * 219 * TODO: Increase the scope of this. 220 */ 221 @Override hasSideEffect()222 public boolean hasSideEffect() { 223 Rop opcode = getOpcode(); 224 225 if (opcode.getBranchingness() != Rop.BRANCH_NONE) { 226 return true; 227 } 228 229 boolean hasLocalSideEffect 230 = Optimizer.getPreserveLocals() && getLocalAssignment() != null; 231 232 switch (opcode.getOpcode()) { 233 case RegOps.MOVE_RESULT: 234 case RegOps.MOVE: 235 case RegOps.CONST: 236 return hasLocalSideEffect; 237 default: 238 return true; 239 } 240 } 241 } 242