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.dex.code;
18 
19 import com.android.dx.rop.cst.Constant;
20 import com.android.dx.rop.type.Type;
21 import 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  */
27 public 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      */
DalvCode(int positionInfo, OutputFinisher unprocessedInsns, CatchBuilder unprocessedCatches)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      */
finishProcessingIfNecessary()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      */
assignIndices(AssignIndicesCallback callback)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      */
hasPositions()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      */
hasLocals()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      */
hasAnyCatches()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      */
getCatchTypes()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      */
getInsnConstants()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      */
getInsns()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      */
getCatches()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      */
getPositions()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      */
getLocals()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          */
getIndex(Constant cst)229         public int getIndex(Constant cst);
230     }
231 }
232