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.dex.code;
18
19import com.android.dx.rop.cst.Constant;
20import com.android.dx.rop.type.Type;
21import java.util.HashSet;
22
23/**
24 * Container for all the pieces of a concrete method. Each instance
25 * corresponds to a {@code code} structure in a {@code .dex} file.
26 */
27public final class DalvCode {
28    /**
29     * how much position info to preserve; one of the static
30     * constants in {@link PositionList}
31     */
32    private final int positionInfo;
33
34    /**
35     * {@code null-ok;} the instruction list, ready for final processing;
36     * nulled out in {@link #finishProcessingIfNecessary}
37     */
38    private OutputFinisher unprocessedInsns;
39
40    /**
41     * {@code non-null;} unprocessed catch table;
42     * nulled out in {@link #finishProcessingIfNecessary}
43     */
44    private CatchBuilder unprocessedCatches;
45
46    /**
47     * {@code null-ok;} catch table; set in
48     * {@link #finishProcessingIfNecessary}
49     */
50    private CatchTable catches;
51
52    /**
53     * {@code null-ok;} source positions list; set in
54     * {@link #finishProcessingIfNecessary}
55     */
56    private PositionList positions;
57
58    /**
59     * {@code null-ok;} local variable list; set in
60     * {@link #finishProcessingIfNecessary}
61     */
62    private LocalList locals;
63
64    /**
65     * {@code null-ok;} the processed instruction list; set in
66     * {@link #finishProcessingIfNecessary}
67     */
68    private DalvInsnList insns;
69
70    /**
71     * Constructs an instance.
72     *
73     * @param positionInfo how much position info to preserve; one of the
74     * static constants in {@link PositionList}
75     * @param unprocessedInsns {@code non-null;} the instruction list, ready
76     * for final processing
77     * @param unprocessedCatches {@code non-null;} unprocessed catch
78     * (exception handler) table
79     */
80    public DalvCode(int positionInfo, OutputFinisher unprocessedInsns,
81            CatchBuilder unprocessedCatches) {
82        if (unprocessedInsns == null) {
83            throw new NullPointerException("unprocessedInsns == null");
84        }
85
86        if (unprocessedCatches == null) {
87            throw new NullPointerException("unprocessedCatches == null");
88        }
89
90        this.positionInfo = positionInfo;
91        this.unprocessedInsns = unprocessedInsns;
92        this.unprocessedCatches = unprocessedCatches;
93        this.catches = null;
94        this.positions = null;
95        this.locals = null;
96        this.insns = null;
97    }
98
99    /**
100     * Finish up processing of the method.
101     */
102    private void finishProcessingIfNecessary() {
103        if (insns != null) {
104            return;
105        }
106
107        insns = unprocessedInsns.finishProcessingAndGetList();
108        positions = PositionList.make(insns, positionInfo);
109        locals = LocalList.make(insns);
110        catches = unprocessedCatches.build();
111
112        // Let them be gc'ed.
113        unprocessedInsns = null;
114        unprocessedCatches = null;
115    }
116
117    /**
118     * Assign indices in all instructions that need them, using the
119     * given callback to perform lookups. This must be called before
120     * {@link #getInsns}.
121     *
122     * @param callback {@code non-null;} callback object
123     */
124    public void assignIndices(AssignIndicesCallback callback) {
125        unprocessedInsns.assignIndices(callback);
126    }
127
128    /**
129     * Gets whether this instance has any position data to represent.
130     *
131     * @return {@code true} iff this instance has any position
132     * data to represent
133     */
134    public boolean hasPositions() {
135        return (positionInfo != PositionList.NONE)
136            && unprocessedInsns.hasAnyPositionInfo();
137    }
138
139    /**
140     * Gets whether this instance has any local variable data to represent.
141     *
142     * @return {@code true} iff this instance has any local variable
143     * data to represent
144     */
145    public boolean hasLocals() {
146        return unprocessedInsns.hasAnyLocalInfo();
147    }
148
149    /**
150     * Gets whether this instance has any catches at all (either typed
151     * or catch-all).
152     *
153     * @return whether this instance has any catches at all
154     */
155    public boolean hasAnyCatches() {
156        return unprocessedCatches.hasAnyCatches();
157    }
158
159    /**
160     * Gets the set of catch types handled anywhere in the code.
161     *
162     * @return {@code non-null;} the set of catch types
163     */
164    public HashSet<Type> getCatchTypes() {
165        return unprocessedCatches.getCatchTypes();
166    }
167
168    /**
169     * Gets the set of all constants referred to by instructions in
170     * the code.
171     *
172     * @return {@code non-null;} the set of constants
173     */
174    public HashSet<Constant> getInsnConstants() {
175        return unprocessedInsns.getAllConstants();
176    }
177
178    /**
179     * Gets the list of instructions.
180     *
181     * @return {@code non-null;} the instruction list
182     */
183    public DalvInsnList getInsns() {
184        finishProcessingIfNecessary();
185        return insns;
186    }
187
188    /**
189     * Gets the catch (exception handler) table.
190     *
191     * @return {@code non-null;} the catch table
192     */
193    public CatchTable getCatches() {
194        finishProcessingIfNecessary();
195        return catches;
196    }
197
198    /**
199     * Gets the source positions list.
200     *
201     * @return {@code non-null;} the source positions list
202     */
203    public PositionList getPositions() {
204        finishProcessingIfNecessary();
205        return positions;
206    }
207
208    /**
209     * Gets the source positions list.
210     *
211     * @return {@code non-null;} the source positions list
212     */
213    public LocalList getLocals() {
214        finishProcessingIfNecessary();
215        return locals;
216    }
217
218    /**
219     * Class used as a callback for {@link #assignIndices}.
220     */
221    public static interface AssignIndicesCallback {
222        /**
223         * Gets the index for the given constant.
224         *
225         * @param cst {@code non-null;} the constant
226         * @return {@code >= -1;} the index or {@code -1} if the constant
227         * shouldn't actually be reified with an index
228         */
229        public int getIndex(Constant cst);
230    }
231}
232