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.RegisterSpec;
22 import com.android.dx.rop.code.RegisterSpecList;
23 import com.android.dx.rop.code.Rop;
24 import com.android.dx.util.ToHuman;
25 
26 /**
27  * An instruction in SSA form
28  */
29 public abstract class SsaInsn implements ToHuman, Cloneable {
30     /** {@code non-null;} the block that contains this instance */
31     private final SsaBasicBlock block;
32 
33     /** {@code null-ok;} result register */
34     private RegisterSpec result;
35 
36     /**
37      * Constructs an instance.
38      *
39      * @param result {@code null-ok;} initial result register. May be changed.
40      * @param block {@code non-null;} block containing this insn. Can
41      * never change.
42      */
SsaInsn(RegisterSpec result, SsaBasicBlock block)43     protected SsaInsn(RegisterSpec result, SsaBasicBlock block) {
44         if (block == null) {
45             throw new NullPointerException("block == null");
46         }
47 
48         this.block = block;
49         this.result = result;
50     }
51 
52     /**
53      * Makes a new SSA insn form a rop insn.
54      *
55      * @param insn {@code non-null;} rop insn
56      * @param block {@code non-null;} owning block
57      * @return {@code non-null;} an appropriately constructed instance
58      */
makeFromRop(Insn insn, SsaBasicBlock block)59     public static SsaInsn makeFromRop(Insn insn, SsaBasicBlock block) {
60         return new NormalSsaInsn(insn, block);
61     }
62 
63     /** {@inheritDoc} */
64     @Override
clone()65     public SsaInsn clone() {
66         try {
67             return (SsaInsn)super.clone();
68         } catch (CloneNotSupportedException ex) {
69             throw new RuntimeException ("unexpected", ex);
70         }
71     }
72 
73     /**
74      * Like {@link com.android.dx.rop.code.Insn getResult()}.
75      *
76      * @return result register
77      */
getResult()78     public RegisterSpec getResult() {
79         return result;
80     }
81 
82     /**
83      * Set the result register.
84      *
85      * @param result {@code non-null;} the new result register
86      */
setResult(RegisterSpec result)87     protected void setResult(RegisterSpec result) {
88         if (result == null) {
89             throw new NullPointerException("result == null");
90         }
91 
92         this.result = result;
93     }
94 
95     /**
96      * Like {@link com.android.dx.rop.code.Insn getSources()}.
97      *
98      * @return {@code non-null;} sources list
99      */
getSources()100     abstract public RegisterSpecList getSources();
101 
102     /**
103      * Gets the block to which this insn instance belongs.
104      *
105      * @return owning block
106      */
getBlock()107     public SsaBasicBlock getBlock() {
108         return block;
109     }
110 
111     /**
112      * Returns whether or not the specified reg is the result reg.
113      *
114      * @param reg register to test
115      * @return true if there is a result and it is stored in the specified
116      * register
117      */
isResultReg(int reg)118     public boolean isResultReg(int reg) {
119         return result != null && result.getReg() == reg;
120     }
121 
122 
123     /**
124      * Changes the result register if this insn has a result. This is used
125      * during renaming.
126      *
127      * @param reg new result register
128      */
changeResultReg(int reg)129     public void changeResultReg(int reg) {
130         if (result != null) {
131             result = result.withReg(reg);
132         }
133     }
134 
135     /**
136      * Sets the local association for the result of this insn. This is
137      * sometimes updated during the SsaRenamer process.
138      *
139      * @param local {@code null-ok;} new debug/local variable info
140      */
setResultLocal(LocalItem local)141     public final void setResultLocal(LocalItem local) {
142         LocalItem oldItem = result.getLocalItem();
143 
144         if (local != oldItem && (local == null
145                 || !local.equals(result.getLocalItem()))) {
146             result = RegisterSpec.makeLocalOptional(
147                     result.getReg(), result.getType(), local);
148         }
149     }
150 
151     /**
152      * Map registers after register allocation.
153      *
154      * @param mapper {@code non-null;} mapping from old to new registers
155      */
mapRegisters(RegisterMapper mapper)156     public final void mapRegisters(RegisterMapper mapper) {
157         RegisterSpec oldResult = result;
158 
159         result = mapper.map(result);
160         block.getParent().updateOneDefinition(this, oldResult);
161         mapSourceRegisters(mapper);
162     }
163 
164     /**
165      * Maps only source registers.
166      *
167      * @param mapper new mapping
168      */
mapSourceRegisters(RegisterMapper mapper)169     abstract public void mapSourceRegisters(RegisterMapper mapper);
170 
171     /**
172      * Returns the Rop opcode for this insn, or null if this is a phi insn.
173      *
174      * TODO: Move this up into NormalSsaInsn.
175      *
176      * @return {@code null-ok;} Rop opcode if there is one.
177      */
getOpcode()178     abstract public Rop getOpcode();
179 
180     /**
181      * Returns the original Rop insn for this insn, or null if this is
182      * a phi insn.
183      *
184      * TODO: Move this up into NormalSsaInsn.
185      *
186      * @return {@code null-ok;} Rop insn if there is one.
187      */
getOriginalRopInsn()188     abstract public Insn getOriginalRopInsn();
189 
190     /**
191      * Gets the spec of a local variable assignment that occurs at this
192      * instruction, or null if no local variable assignment occurs. This
193      * may be the result register, or for {@code mark-local} insns
194      * it may be the source.
195      *
196      * @see com.android.dx.rop.code.Insn#getLocalAssignment()
197      *
198      * @return {@code null-ok;} a local-associated register spec or null
199      */
getLocalAssignment()200     public RegisterSpec getLocalAssignment() {
201         if (result != null && result.getLocalItem() != null) {
202             return result;
203         }
204 
205         return null;
206     }
207 
208     /**
209      * Indicates whether the specified register is amongst the registers
210      * used as sources for this instruction.
211      *
212      * @param reg the register in question
213      * @return true if the reg is a source
214      */
isRegASource(int reg)215     public boolean isRegASource(int reg) {
216         return null != getSources().specForRegister(reg);
217     }
218 
219     /**
220      * Transform back to ROP form.
221      *
222      * TODO: Move this up into NormalSsaInsn.
223      *
224      * @return {@code non-null;} a ROP representation of this instruction, with
225      * updated registers.
226      */
toRopInsn()227     public abstract Insn toRopInsn();
228 
229     /**
230      * @return true if this is a PhiInsn or a normal move insn
231      */
isPhiOrMove()232     public abstract boolean isPhiOrMove();
233 
234     /**
235      * Returns true if this insn is considered to have a side effect beyond
236      * that of assigning to the result reg.
237      *
238      * @return true if this insn is considered to have a side effect beyond
239      * that of assigning to the result reg.
240      */
hasSideEffect()241     public abstract boolean hasSideEffect();
242 
243     /**
244      * @return true if this is a move (but not a move-operand or
245      * move-exception) instruction
246      */
isNormalMoveInsn()247     public boolean isNormalMoveInsn() {
248         return false;
249     }
250 
251     /**
252      * @return true if this is a move-exception instruction.
253      * These instructions must immediately follow a preceeding invoke*
254      */
isMoveException()255     public boolean isMoveException() {
256         return false;
257     }
258 
259     /**
260      * @return true if this instruction can throw.
261      */
canThrow()262     abstract public boolean canThrow();
263 
264     /**
265      * Accepts a visitor.
266      *
267      * @param v {@code non-null} the visitor
268      */
accept(Visitor v)269     public abstract void accept(Visitor v);
270 
271     /**
272      * Visitor interface for this class.
273      */
274     public static interface Visitor {
275         /**
276          * Any non-phi move instruction
277          * @param insn {@code non-null;} the instruction to visit
278          */
visitMoveInsn(NormalSsaInsn insn)279         public void visitMoveInsn(NormalSsaInsn insn);
280 
281         /**
282          * Any phi insn
283          * @param insn {@code non-null;} the instruction to visit
284          */
visitPhiInsn(PhiInsn insn)285         public void visitPhiInsn(PhiInsn insn);
286 
287         /**
288          * Any insn that isn't a move or a phi (which is also a move).
289          * @param insn {@code non-null;} the instruction to visit
290          */
visitNonMoveInsn(NormalSsaInsn insn)291         public void visitNonMoveInsn(NormalSsaInsn insn);
292     }
293 }
294