| /* |
| * Copyright (C) 2007 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.dx.ssa; |
| |
| import com.android.dx.rop.code.*; |
| |
| /** |
| * A "normal" (non-phi) instruction in SSA form. Always wraps a rop insn. |
| */ |
| public final class NormalSsaInsn extends SsaInsn implements Cloneable { |
| /** {@code non-null;} rop insn that we're wrapping */ |
| private Insn insn; |
| |
| /** |
| * Creates an instance. |
| * |
| * @param insn Rop insn to wrap |
| * @param block block that contains this insn |
| */ |
| NormalSsaInsn(final Insn insn, final SsaBasicBlock block) { |
| super(insn.getResult(), block); |
| this.insn = insn; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public final void mapSourceRegisters(RegisterMapper mapper) { |
| RegisterSpecList oldSources = insn.getSources(); |
| RegisterSpecList newSources = mapper.map(oldSources); |
| |
| if (newSources != oldSources) { |
| insn = insn.withNewRegisters(getResult(), newSources); |
| getBlock().getParent().onSourcesChanged(this, oldSources); |
| } |
| } |
| |
| /** |
| * Changes one of the insn's sources. New source should be of same type |
| * and category. |
| * |
| * @param index {@code >=0;} index of source to change |
| * @param newSpec spec for new source |
| */ |
| public final void changeOneSource(int index, RegisterSpec newSpec) { |
| RegisterSpecList origSources = insn.getSources(); |
| int sz = origSources.size(); |
| RegisterSpecList newSources = new RegisterSpecList(sz); |
| |
| for (int i = 0; i < sz; i++) { |
| newSources.set(i, i == index ? newSpec : origSources.get(i)); |
| } |
| |
| newSources.setImmutable(); |
| |
| RegisterSpec origSpec = origSources.get(index); |
| if (origSpec.getReg() != newSpec.getReg()) { |
| /* |
| * If the register remains unchanged, we're only changing |
| * the type or local var name so don't update use list |
| */ |
| getBlock().getParent().onSourceChanged(this, origSpec, newSpec); |
| } |
| |
| insn = insn.withNewRegisters(getResult(), newSources); |
| } |
| |
| /** |
| * Changes the source list of the insn. New source list should be the |
| * same size and consist of sources of identical types. |
| * |
| * @param newSources non-null new sources list. |
| */ |
| public final void setNewSources (RegisterSpecList newSources) { |
| RegisterSpecList origSources = insn.getSources(); |
| |
| if (origSources.size() != newSources.size()) { |
| throw new RuntimeException("Sources counts don't match"); |
| } |
| |
| insn = insn.withNewRegisters(getResult(), newSources); |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public NormalSsaInsn clone() { |
| return (NormalSsaInsn) super.clone(); |
| } |
| |
| /** |
| * Like rop.Insn.getSources(). |
| * |
| * @return {@code null-ok;} sources list |
| */ |
| @Override |
| public RegisterSpecList getSources() { |
| return insn.getSources(); |
| } |
| |
| /** {@inheritDoc} */ |
| public String toHuman() { |
| return toRopInsn().toHuman(); |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public Insn toRopInsn() { |
| return insn.withNewRegisters(getResult(), insn.getSources()); |
| } |
| |
| /** |
| * @return the Rop opcode for this insn |
| */ |
| @Override |
| public Rop getOpcode() { |
| return insn.getOpcode(); |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public Insn getOriginalRopInsn() { |
| return insn; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public RegisterSpec getLocalAssignment() { |
| RegisterSpec assignment; |
| |
| if (insn.getOpcode().getOpcode() == RegOps.MARK_LOCAL) { |
| assignment = insn.getSources().get(0); |
| } else { |
| assignment = getResult(); |
| } |
| |
| if (assignment == null) { |
| return null; |
| } |
| |
| LocalItem local = assignment.getLocalItem(); |
| |
| if (local == null) { |
| return null; |
| } |
| |
| return assignment; |
| } |
| |
| /** |
| * Upgrades this insn to a version that represents the constant source |
| * literally. If the upgrade is not possible, this does nothing. |
| * |
| * @see Insn#withSourceLiteral |
| */ |
| public void upgradeToLiteral() { |
| RegisterSpecList oldSources = insn.getSources(); |
| |
| insn = insn.withSourceLiteral(); |
| getBlock().getParent().onSourcesChanged(this, oldSources); |
| } |
| |
| /** |
| * @return true if this is a move (but not a move-operand) instruction |
| */ |
| @Override |
| public boolean isNormalMoveInsn() { |
| return insn.getOpcode().getOpcode() == RegOps.MOVE; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public boolean isMoveException() { |
| return insn.getOpcode().getOpcode() == RegOps.MOVE_EXCEPTION; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public boolean canThrow() { |
| return insn.canThrow(); |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public void accept(Visitor v) { |
| if (isNormalMoveInsn()) { |
| v.visitMoveInsn(this); |
| } else { |
| v.visitNonMoveInsn(this); |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public boolean isPhiOrMove() { |
| return isNormalMoveInsn(); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * TODO: Increase the scope of this. |
| */ |
| @Override |
| public boolean hasSideEffect() { |
| Rop opcode = getOpcode(); |
| |
| if (opcode.getBranchingness() != Rop.BRANCH_NONE) { |
| return true; |
| } |
| |
| boolean hasLocalSideEffect |
| = Optimizer.getPreserveLocals() && getLocalAssignment() != null; |
| |
| switch (opcode.getOpcode()) { |
| case RegOps.MOVE_RESULT: |
| case RegOps.MOVE: |
| case RegOps.CONST: |
| return hasLocalSideEffect; |
| default: |
| return true; |
| } |
| } |
| } |