/* * 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.*; import com.android.dx.util.ToHuman; /** * An instruction in SSA form */ public abstract class SsaInsn implements ToHuman, Cloneable { /** {@code non-null;} the block that contains this instance */ private final SsaBasicBlock block; /** {@code null-ok;} result register */ private RegisterSpec result; /** * Constructs an instance. * * @param result {@code null-ok;} initial result register. May be changed. * @param block {@code non-null;} block containing this insn. Can * never change. */ protected SsaInsn(RegisterSpec result, SsaBasicBlock block) { if (block == null) { throw new NullPointerException("block == null"); } this.block = block; this.result = result; } /** * Makes a new SSA insn form a rop insn. * * @param insn {@code non-null;} rop insn * @param block {@code non-null;} owning block * @return {@code non-null;} an appropriately constructed instance */ public static SsaInsn makeFromRop(Insn insn, SsaBasicBlock block) { return new NormalSsaInsn(insn, block); } /** {@inheritDoc} */ @Override public SsaInsn clone() { try { return (SsaInsn)super.clone(); } catch (CloneNotSupportedException ex) { throw new RuntimeException ("unexpected", ex); } } /** * Like {@link com.android.dx.rop.code.Insn getResult()}. * * @return result register */ public RegisterSpec getResult() { return result; } /** * Set the result register. * * @param result {@code non-null;} the new result register */ protected void setResult(RegisterSpec result) { if (result == null) { throw new NullPointerException("result == null"); } this.result = result; } /** * Like {@link com.android.dx.rop.code.Insn getSources()}. * * @return {@code non-null;} sources list */ abstract public RegisterSpecList getSources(); /** * Gets the block to which this insn instance belongs. * * @return owning block */ public SsaBasicBlock getBlock() { return block; } /** * Returns whether or not the specified reg is the result reg. * * @param reg register to test * @return true if there is a result and it is stored in the specified * register */ public boolean isResultReg(int reg) { return result != null && result.getReg() == reg; } /** * Changes the result register if this insn has a result. This is used * during renaming. * * @param reg new result register */ public void changeResultReg(int reg) { if (result != null) { result = result.withReg(reg); } } /** * Sets the local association for the result of this insn. This is * sometimes updated during the SsaRenamer process. * * @param local {@code null-ok;} new debug/local variable info */ public final void setResultLocal(LocalItem local) { LocalItem oldItem = result.getLocalItem(); if (local != oldItem && (local == null || !local.equals(result.getLocalItem()))) { result = RegisterSpec.makeLocalOptional( result.getReg(), result.getType(), local); } } /** * Map registers after register allocation. * * @param mapper {@code non-null;} mapping from old to new registers */ public final void mapRegisters(RegisterMapper mapper) { RegisterSpec oldResult = result; result = mapper.map(result); block.getParent().updateOneDefinition(this, oldResult); mapSourceRegisters(mapper); } /** * Maps only source registers. * * @param mapper new mapping */ abstract public void mapSourceRegisters(RegisterMapper mapper); /** * Returns the Rop opcode for this insn, or null if this is a phi insn. * * TODO: Move this up into NormalSsaInsn. * * @return {@code null-ok;} Rop opcode if there is one. */ abstract public Rop getOpcode(); /** * Returns the original Rop insn for this insn, or null if this is * a phi insn. * * TODO: Move this up into NormalSsaInsn. * * @return {@code null-ok;} Rop insn if there is one. */ abstract public Insn getOriginalRopInsn(); /** * Gets the spec of a local variable assignment that occurs at this * instruction, or null if no local variable assignment occurs. This * may be the result register, or for {@code mark-local} insns * it may be the source. * * @see com.android.dx.rop.code.Insn#getLocalAssignment() * * @return {@code null-ok;} a local-associated register spec or null */ public RegisterSpec getLocalAssignment() { if (result != null && result.getLocalItem() != null) { return result; } return null; } /** * Indicates whether the specified register is amongst the registers * used as sources for this instruction. * * @param reg the register in question * @return true if the reg is a source */ public boolean isRegASource(int reg) { return null != getSources().specForRegister(reg); } /** * Transform back to ROP form. * * TODO: Move this up into NormalSsaInsn. * * @return {@code non-null;} a ROP representation of this instruction, with * updated registers. */ public abstract Insn toRopInsn(); /** * @return true if this is a PhiInsn or a normal move insn */ public abstract boolean isPhiOrMove(); /** * Returns true if this insn is considered to have a side effect beyond * that of assigning to the result reg. * * @return true if this insn is considered to have a side effect beyond * that of assigning to the result reg. */ public abstract boolean hasSideEffect(); /** * @return true if this is a move (but not a move-operand or * move-exception) instruction */ public boolean isNormalMoveInsn() { return false; } /** * @return true if this is a move-exception instruction. * These instructions must immediately follow a preceeding invoke* */ public boolean isMoveException() { return false; } /** * @return true if this instruction can throw. */ abstract public boolean canThrow(); /** * Accepts a visitor. * * @param v {@code non-null} the visitor */ public abstract void accept(Visitor v); /** * Visitor interface for this class. */ public static interface Visitor { /** * Any non-phi move instruction * @param insn {@code non-null;} the instruction to visit */ public void visitMoveInsn(NormalSsaInsn insn); /** * Any phi insn * @param insn {@code non-null;} the instruction to visit */ public void visitPhiInsn(PhiInsn insn); /** * Any insn that isn't a move or a phi (which is also a move). * @param insn {@code non-null;} the instruction to visit */ public void visitNonMoveInsn(NormalSsaInsn insn); } }