OSDN Git Service

Mechanical refactoring of dx into two parts.
[android-x86/dalvik.git] / dx / src / com / android / dx / ssa / NormalSsaInsn.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.RegOps;
22 import com.android.dx.rop.code.RegisterSpec;
23 import com.android.dx.rop.code.RegisterSpecList;
24 import com.android.dx.rop.code.Rop;
25
26 /**
27  * A "normal" (non-phi) instruction in SSA form. Always wraps a rop insn.
28  */
29 public final class NormalSsaInsn extends SsaInsn implements Cloneable {
30     /** {@code non-null;} rop insn that we're wrapping */
31     private Insn insn;
32
33     /**
34      * Creates an instance.
35      *
36      * @param insn Rop insn to wrap
37      * @param block block that contains this insn
38      */
39     NormalSsaInsn(final Insn insn, final SsaBasicBlock block) {
40         super(insn.getResult(), block);
41         this.insn = insn;
42     }
43
44     /** {@inheritDoc} */
45     @Override
46     public final void mapSourceRegisters(RegisterMapper mapper) {
47         RegisterSpecList oldSources = insn.getSources();
48         RegisterSpecList newSources = mapper.map(oldSources);
49
50         if (newSources != oldSources) {
51             insn = insn.withNewRegisters(getResult(), newSources);
52             getBlock().getParent().onSourcesChanged(this, oldSources);
53         }
54     }
55
56     /**
57      * Changes one of the insn's sources. New source should be of same type
58      * and category.
59      *
60      * @param index {@code >=0;} index of source to change
61      * @param newSpec spec for new source
62      */
63     public final void changeOneSource(int index, RegisterSpec newSpec) {
64         RegisterSpecList origSources = insn.getSources();
65         int sz = origSources.size();
66         RegisterSpecList newSources = new RegisterSpecList(sz);
67
68         for (int i = 0; i < sz; i++) {
69             newSources.set(i, i == index ? newSpec : origSources.get(i));
70         }
71
72         newSources.setImmutable();
73
74         RegisterSpec origSpec = origSources.get(index);
75         if (origSpec.getReg() != newSpec.getReg()) {
76             /*
77              * If the register remains unchanged, we're only changing
78              * the type or local var name so don't update use list
79              */
80             getBlock().getParent().onSourceChanged(this, origSpec, newSpec);
81         }
82
83         insn = insn.withNewRegisters(getResult(), newSources);
84     }
85
86     /**
87      * Changes the source list of the insn. New source list should be the
88      * same size and consist of sources of identical types.
89      *
90      * @param newSources non-null new sources list.
91      */
92     public final void setNewSources (RegisterSpecList newSources) {
93         RegisterSpecList origSources = insn.getSources();
94
95         if (origSources.size() != newSources.size()) {
96             throw new RuntimeException("Sources counts don't match");
97         }
98
99         insn = insn.withNewRegisters(getResult(), newSources);
100     }
101
102     /** {@inheritDoc} */
103     @Override
104     public NormalSsaInsn clone() {
105         return (NormalSsaInsn) super.clone();
106     }
107
108     /**
109      * Like rop.Insn.getSources().
110      *
111      * @return {@code null-ok;} sources list
112      */
113     @Override
114     public RegisterSpecList getSources() {
115         return insn.getSources();
116     }
117
118     /** {@inheritDoc} */
119     public String toHuman() {
120         return toRopInsn().toHuman();
121     }
122
123     /** {@inheritDoc} */
124     @Override
125     public Insn toRopInsn() {
126         return insn.withNewRegisters(getResult(), insn.getSources());
127     }
128
129     /**
130      * @return the Rop opcode for this insn
131      */
132     @Override
133     public Rop getOpcode() {
134         return insn.getOpcode();
135     }
136
137     /** {@inheritDoc} */
138     @Override
139     public Insn getOriginalRopInsn() {
140         return insn;
141     }
142
143     /** {@inheritDoc} */
144     @Override
145     public RegisterSpec getLocalAssignment() {
146         RegisterSpec assignment;
147
148         if (insn.getOpcode().getOpcode() == RegOps.MARK_LOCAL) {
149             assignment = insn.getSources().get(0);
150         } else {
151             assignment = getResult();
152         }
153
154         if (assignment == null) {
155             return null;
156         }
157
158         LocalItem local = assignment.getLocalItem();
159
160         if (local == null) {
161             return null;
162         }
163
164         return assignment;
165     }
166
167     /**
168      * Upgrades this insn to a version that represents the constant source
169      * literally. If the upgrade is not possible, this does nothing.
170      *
171      * @see Insn#withSourceLiteral
172      */
173     public void upgradeToLiteral() {
174         RegisterSpecList oldSources = insn.getSources();
175
176         insn = insn.withSourceLiteral();
177         getBlock().getParent().onSourcesChanged(this, oldSources);
178     }
179
180     /**
181      * @return true if this is a move (but not a move-operand) instruction
182      */
183     @Override
184     public boolean isNormalMoveInsn() {
185         return insn.getOpcode().getOpcode() == RegOps.MOVE;
186     }
187
188     /** {@inheritDoc} */
189     @Override
190     public boolean isMoveException() {
191         return insn.getOpcode().getOpcode() == RegOps.MOVE_EXCEPTION;
192     }
193
194     /** {@inheritDoc} */
195     @Override
196     public boolean canThrow() {
197         return insn.canThrow();
198     }
199
200     /** {@inheritDoc} */
201     @Override
202     public void accept(Visitor v) {
203         if (isNormalMoveInsn()) {
204             v.visitMoveInsn(this);
205         } else {
206             v.visitNonMoveInsn(this);
207         }
208     }
209
210     /** {@inheritDoc} */
211     @Override
212     public  boolean isPhiOrMove() {
213         return isNormalMoveInsn();
214     }
215
216     /**
217      * {@inheritDoc}
218      *
219      * TODO: Increase the scope of this.
220      */
221     @Override
222     public boolean hasSideEffect() {
223         Rop opcode = getOpcode();
224
225         if (opcode.getBranchingness() != Rop.BRANCH_NONE) {
226             return true;
227         }
228
229         boolean hasLocalSideEffect
230             = Optimizer.getPreserveLocals() && getLocalAssignment() != null;
231
232         switch (opcode.getOpcode()) {
233             case RegOps.MOVE_RESULT:
234             case RegOps.MOVE:
235             case RegOps.CONST:
236                 return hasLocalSideEffect;
237             default:
238                 return true;
239         }
240     }
241 }