OSDN Git Service

Mechanical refactoring of dx into two parts.
[android-x86/dalvik.git] / dx / src / com / android / dx / ssa / SsaInsn.java
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      */
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      */
59     public static SsaInsn makeFromRop(Insn insn, SsaBasicBlock block) {
60         return new NormalSsaInsn(insn, block);
61     }
62
63     /** {@inheritDoc} */
64     @Override
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      */
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      */
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      */
100     abstract public RegisterSpecList getSources();
101
102     /**
103      * Gets the block to which this insn instance belongs.
104      *
105      * @return owning block
106      */
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      */
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      */
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      */
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      */
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      */
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      */
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      */
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      */
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      */
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      */
227     public abstract Insn toRopInsn();
228
229     /**
230      * @return true if this is a PhiInsn or a normal move insn
231      */
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      */
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      */
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      */
255     public boolean isMoveException() {
256         return false;
257     }
258
259     /**
260      * @return true if this instruction can throw.
261      */
262     abstract public boolean canThrow();
263
264     /**
265      * Accepts a visitor.
266      *
267      * @param v {@code non-null} the visitor
268      */
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          */
279         public void visitMoveInsn(NormalSsaInsn insn);
280
281         /**
282          * Any phi insn
283          * @param insn {@code non-null;} the instruction to visit
284          */
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          */
291         public void visitNonMoveInsn(NormalSsaInsn insn);
292     }
293 }