OSDN Git Service

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