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