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