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