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