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      */
NormalSsaInsn(final Insn insn, final SsaBasicBlock block)39     NormalSsaInsn(final Insn insn, final SsaBasicBlock block) {
40         super(insn.getResult(), block);
41         this.insn = insn;
42     }
43 
44     /** {@inheritDoc} */
45     @Override
mapSourceRegisters(RegisterMapper mapper)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      */
changeOneSource(int index, RegisterSpec newSpec)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      */
setNewSources(RegisterSpecList newSources)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
clone()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
getSources()114     public RegisterSpecList getSources() {
115         return insn.getSources();
116     }
117 
118     /** {@inheritDoc} */
119     @Override
toHuman()120     public String toHuman() {
121         return toRopInsn().toHuman();
122     }
123 
124     /** {@inheritDoc} */
125     @Override
toRopInsn()126     public Insn toRopInsn() {
127         return insn.withNewRegisters(getResult(), insn.getSources());
128     }
129 
130     /**
131      * @return the Rop opcode for this insn
132      */
133     @Override
getOpcode()134     public Rop getOpcode() {
135         return insn.getOpcode();
136     }
137 
138     /** {@inheritDoc} */
139     @Override
getOriginalRopInsn()140     public Insn getOriginalRopInsn() {
141         return insn;
142     }
143 
144     /** {@inheritDoc} */
145     @Override
getLocalAssignment()146     public RegisterSpec getLocalAssignment() {
147         RegisterSpec assignment;
148 
149         if (insn.getOpcode().getOpcode() == RegOps.MARK_LOCAL) {
150             assignment = insn.getSources().get(0);
151         } else {
152             assignment = getResult();
153         }
154 
155         if (assignment == null) {
156             return null;
157         }
158 
159         LocalItem local = assignment.getLocalItem();
160 
161         if (local == null) {
162             return null;
163         }
164 
165         return assignment;
166     }
167 
168     /**
169      * Upgrades this insn to a version that represents the constant source
170      * literally. If the upgrade is not possible, this does nothing.
171      *
172      * @see Insn#withSourceLiteral
173      */
upgradeToLiteral()174     public void upgradeToLiteral() {
175         RegisterSpecList oldSources = insn.getSources();
176 
177         insn = insn.withSourceLiteral();
178         getBlock().getParent().onSourcesChanged(this, oldSources);
179     }
180 
181     /**
182      * @return true if this is a move (but not a move-operand) instruction
183      */
184     @Override
isNormalMoveInsn()185     public boolean isNormalMoveInsn() {
186         return insn.getOpcode().getOpcode() == RegOps.MOVE;
187     }
188 
189     /** {@inheritDoc} */
190     @Override
isMoveException()191     public boolean isMoveException() {
192         return insn.getOpcode().getOpcode() == RegOps.MOVE_EXCEPTION;
193     }
194 
195     /** {@inheritDoc} */
196     @Override
canThrow()197     public boolean canThrow() {
198         return insn.canThrow();
199     }
200 
201     /** {@inheritDoc} */
202     @Override
accept(Visitor v)203     public void accept(Visitor v) {
204         if (isNormalMoveInsn()) {
205             v.visitMoveInsn(this);
206         } else {
207             v.visitNonMoveInsn(this);
208         }
209     }
210 
211     /** {@inheritDoc} */
212     @Override
isPhiOrMove()213     public  boolean isPhiOrMove() {
214         return isNormalMoveInsn();
215     }
216 
217     /**
218      * {@inheritDoc}
219      *
220      * TODO: Increase the scope of this.
221      */
222     @Override
hasSideEffect()223     public boolean hasSideEffect() {
224         Rop opcode = getOpcode();
225 
226         if (opcode.getBranchingness() != Rop.BRANCH_NONE) {
227             return true;
228         }
229 
230         boolean hasLocalSideEffect
231             = Optimizer.getPreserveLocals() && getLocalAssignment() != null;
232 
233         switch (opcode.getOpcode()) {
234             case RegOps.MOVE_RESULT:
235             case RegOps.MOVE:
236             case RegOps.CONST:
237                 return hasLocalSideEffect;
238             default:
239                 return true;
240         }
241     }
242 }
243