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} */ 119 @Override toHuman()120 public String toHuman() { 121 return toRopInsn().toHuman(); 122 } 123 124 /** {@inheritDoc} */ 125 @Override toRopInsn()126 public Insn toRopInsn() { 127 return insn.withNewRegisters(getResult(), insn.getSources()); 128 } 129 130 /** 131 * @return the Rop opcode for this insn 132 */ 133 @Override getOpcode()134 public Rop getOpcode() { 135 return insn.getOpcode(); 136 } 137 138 /** {@inheritDoc} */ 139 @Override getOriginalRopInsn()140 public Insn getOriginalRopInsn() { 141 return insn; 142 } 143 144 /** {@inheritDoc} */ 145 @Override getLocalAssignment()146 public RegisterSpec getLocalAssignment() { 147 RegisterSpec assignment; 148 149 if (insn.getOpcode().getOpcode() == RegOps.MARK_LOCAL) { 150 assignment = insn.getSources().get(0); 151 } else { 152 assignment = getResult(); 153 } 154 155 if (assignment == null) { 156 return null; 157 } 158 159 LocalItem local = assignment.getLocalItem(); 160 161 if (local == null) { 162 return null; 163 } 164 165 return assignment; 166 } 167 168 /** 169 * Upgrades this insn to a version that represents the constant source 170 * literally. If the upgrade is not possible, this does nothing. 171 * 172 * @see Insn#withSourceLiteral 173 */ upgradeToLiteral()174 public void upgradeToLiteral() { 175 RegisterSpecList oldSources = insn.getSources(); 176 177 insn = insn.withSourceLiteral(); 178 getBlock().getParent().onSourcesChanged(this, oldSources); 179 } 180 181 /** 182 * @return true if this is a move (but not a move-operand) instruction 183 */ 184 @Override isNormalMoveInsn()185 public boolean isNormalMoveInsn() { 186 return insn.getOpcode().getOpcode() == RegOps.MOVE; 187 } 188 189 /** {@inheritDoc} */ 190 @Override isMoveException()191 public boolean isMoveException() { 192 return insn.getOpcode().getOpcode() == RegOps.MOVE_EXCEPTION; 193 } 194 195 /** {@inheritDoc} */ 196 @Override canThrow()197 public boolean canThrow() { 198 return insn.canThrow(); 199 } 200 201 /** {@inheritDoc} */ 202 @Override accept(Visitor v)203 public void accept(Visitor v) { 204 if (isNormalMoveInsn()) { 205 v.visitMoveInsn(this); 206 } else { 207 v.visitNonMoveInsn(this); 208 } 209 } 210 211 /** {@inheritDoc} */ 212 @Override isPhiOrMove()213 public boolean isPhiOrMove() { 214 return isNormalMoveInsn(); 215 } 216 217 /** 218 * {@inheritDoc} 219 * 220 * TODO: Increase the scope of this. 221 */ 222 @Override hasSideEffect()223 public boolean hasSideEffect() { 224 Rop opcode = getOpcode(); 225 226 if (opcode.getBranchingness() != Rop.BRANCH_NONE) { 227 return true; 228 } 229 230 boolean hasLocalSideEffect 231 = Optimizer.getPreserveLocals() && getLocalAssignment() != null; 232 233 switch (opcode.getOpcode()) { 234 case RegOps.MOVE_RESULT: 235 case RegOps.MOVE: 236 case RegOps.CONST: 237 return hasLocalSideEffect; 238 default: 239 return true; 240 } 241 } 242 } 243