• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.rop.code;
18 
19 import com.android.dx.rop.type.StdTypeList;
20 import com.android.dx.rop.type.TypeList;
21 import com.android.dx.util.Hex;
22 import com.android.dx.util.IntList;
23 import com.android.dx.util.LabeledList;
24 
25 /**
26  * List of {@link BasicBlock} instances.
27  */
28 public final class BasicBlockList extends LabeledList {
29     /**
30      * {@code >= -1;} the count of registers required by this method or
31      * {@code -1} if not yet calculated
32      */
33     private int regCount;
34 
35     /**
36      * Constructs an instance. All indices initially contain {@code null},
37      * and the first-block label is initially {@code -1}.
38      *
39      * @param size the size of the list
40      */
BasicBlockList(int size)41     public BasicBlockList(int size) {
42         super(size);
43 
44         regCount = -1;
45     }
46 
47     /**
48      * Constructs a mutable copy for {@code getMutableCopy()}.
49      *
50      * @param old block to copy
51      */
BasicBlockList(BasicBlockList old)52     private BasicBlockList(BasicBlockList old) {
53         super(old);
54         regCount = old.regCount;
55     }
56 
57 
58     /**
59      * Gets the element at the given index. It is an error to call
60      * this with the index for an element which was never set; if you
61      * do that, this will throw {@code NullPointerException}.
62      *
63      * @param n {@code >= 0, < size();} which index
64      * @return {@code non-null;} element at that index
65      */
get(int n)66     public BasicBlock get(int n) {
67         return (BasicBlock) get0(n);
68     }
69 
70     /**
71      * Sets the basic block at the given index.
72      *
73      * @param n {@code >= 0, < size();} which index
74      * @param bb {@code null-ok;} the element to set at {@code n}
75      */
set(int n, BasicBlock bb)76     public void set(int n, BasicBlock bb) {
77         super.set(n, bb);
78 
79         // Reset regCount, since it will need to be recalculated.
80         regCount = -1;
81     }
82 
83     /**
84      * Returns how many registers this method requires. This is simply
85      * the maximum of register-number-plus-category referred to by this
86      * instance's instructions (indirectly through {@link BasicBlock}
87      * instances).
88      *
89      * @return {@code >= 0;} the register count
90      */
getRegCount()91     public int getRegCount() {
92         if (regCount == -1) {
93             RegCountVisitor visitor = new RegCountVisitor();
94             forEachInsn(visitor);
95             regCount = visitor.getRegCount();
96         }
97 
98         return regCount;
99     }
100 
101     /**
102      * Gets the total instruction count for this instance. This is the
103      * sum of the instruction counts of each block.
104      *
105      * @return {@code >= 0;} the total instruction count
106      */
getInstructionCount()107     public int getInstructionCount() {
108         int sz = size();
109         int result = 0;
110 
111         for (int i = 0; i < sz; i++) {
112             BasicBlock one = (BasicBlock) getOrNull0(i);
113             if (one != null) {
114                 result += one.getInsns().size();
115             }
116         }
117 
118         return result;
119     }
120 
121     /**
122      * Gets the total instruction count for this instance, ignoring
123      * mark-local instructions which are not actually emitted.
124      *
125      * @return {@code >= 0;} the total instruction count
126      */
getEffectiveInstructionCount()127     public int getEffectiveInstructionCount() {
128         int sz = size();
129         int result = 0;
130 
131         for (int i = 0; i < sz; i++) {
132             BasicBlock one = (BasicBlock) getOrNull0(i);
133             if (one != null) {
134                 InsnList insns = one.getInsns();
135                 int insnsSz = insns.size();
136 
137                 for (int j = 0; j < insnsSz; j++) {
138                     Insn insn = insns.get(j);
139 
140                     if (insn.getOpcode().getOpcode() != RegOps.MARK_LOCAL) {
141                         result++;
142                     }
143                 }
144             }
145         }
146 
147         return result;
148     }
149 
150     /**
151      * Gets the first block in the list with the given label, if any.
152      *
153      * @param label {@code label >= 0;} the label to look for
154      * @return {@code non-null;} the so-labelled block
155      * @throws IllegalArgumentException thrown if the label isn't found
156      */
labelToBlock(int label)157     public BasicBlock labelToBlock(int label) {
158         int idx = indexOfLabel(label);
159 
160         if (idx < 0) {
161             throw new IllegalArgumentException("no such label: "
162                     + Hex.u2(label));
163         }
164 
165         return get(idx);
166     }
167 
168     /**
169      * Visits each instruction of each block in the list, in order.
170      *
171      * @param visitor {@code non-null;} visitor to use
172      */
forEachInsn(Insn.Visitor visitor)173     public void forEachInsn(Insn.Visitor visitor) {
174         int sz = size();
175 
176         for (int i = 0; i < sz; i++) {
177             BasicBlock one = get(i);
178             InsnList insns = one.getInsns();
179             insns.forEach(visitor);
180         }
181     }
182 
183     /**
184      * Returns an instance that is identical to this one, except that
185      * the registers in each instruction are offset by the given
186      * amount. Mutability of the result is inherited from the
187      * original.
188      *
189      * @param delta the amount to offset register numbers by
190      * @return {@code non-null;} an appropriately-constructed instance
191      */
withRegisterOffset(int delta)192     public BasicBlockList withRegisterOffset(int delta) {
193         int sz = size();
194         BasicBlockList result = new BasicBlockList(sz);
195 
196         for (int i = 0; i < sz; i++) {
197             BasicBlock one = (BasicBlock) get0(i);
198             if (one != null) {
199                 result.set(i, one.withRegisterOffset(delta));
200             }
201         }
202 
203         if (isImmutable()) {
204             result.setImmutable();
205         }
206 
207         return result;
208     }
209 
210     /**
211      * Returns a mutable copy of this list.
212      *
213      * @return {@code non-null;} an appropriately-constructed instance
214      */
getMutableCopy()215     public BasicBlockList getMutableCopy() {
216         return new BasicBlockList(this);
217     }
218 
219     /**
220      * Gets the preferred successor for the given block. If the block
221      * only has one successor, then that is the preferred successor.
222      * Otherwise, if the block has a primay successor, then that is
223      * the preferred successor. If the block has no successors, then
224      * this returns {@code null}.
225      *
226      * @param block {@code non-null;} the block in question
227      * @return {@code null-ok;} the preferred successor, if any
228      */
preferredSuccessorOf(BasicBlock block)229     public BasicBlock preferredSuccessorOf(BasicBlock block) {
230         int primarySuccessor = block.getPrimarySuccessor();
231         IntList successors = block.getSuccessors();
232         int succSize = successors.size();
233 
234         switch (succSize) {
235             case 0: {
236                 return null;
237             }
238             case 1: {
239                 return labelToBlock(successors.get(0));
240             }
241         }
242 
243         if (primarySuccessor != -1) {
244             return labelToBlock(primarySuccessor);
245         } else {
246             return labelToBlock(successors.get(0));
247         }
248     }
249 
250     /**
251      * Compares the catches of two blocks for equality. This includes
252      * both the catch types and target labels.
253      *
254      * @param block1 {@code non-null;} one block to compare
255      * @param block2 {@code non-null;} the other block to compare
256      * @return {@code true} if the two blocks' non-primary successors
257      * are identical
258      */
catchesEqual(BasicBlock block1, BasicBlock block2)259     public boolean catchesEqual(BasicBlock block1, BasicBlock block2) {
260         TypeList catches1 = block1.getExceptionHandlerTypes();
261         TypeList catches2 = block2.getExceptionHandlerTypes();
262 
263         if (!StdTypeList.equalContents(catches1, catches2)) {
264             return false;
265         }
266 
267         IntList succ1 = block1.getSuccessors();
268         IntList succ2 = block2.getSuccessors();
269         int size = succ1.size(); // Both are guaranteed to be the same size.
270 
271         int primary1 = block1.getPrimarySuccessor();
272         int primary2 = block2.getPrimarySuccessor();
273 
274         if (((primary1 == -1) || (primary2 == -1))
275                 && (primary1 != primary2)) {
276             /*
277              * For the current purpose, both blocks in question must
278              * either both have a primary or both not have a primary to
279              * be considered equal, and it turns out here that that's not
280              * the case.
281              */
282             return false;
283         }
284 
285         for (int i = 0; i < size; i++) {
286             int label1 = succ1.get(i);
287             int label2 = succ2.get(i);
288 
289             if (label1 == primary1) {
290                 /*
291                  * It should be the case that block2's primary is at the
292                  * same index. If not, we consider the blocks unequal for
293                  * the current purpose.
294                  */
295                 if (label2 != primary2) {
296                     return false;
297                 }
298                 continue;
299             }
300 
301             if (label1 != label2) {
302                 return false;
303             }
304         }
305 
306         return true;
307     }
308 
309     /**
310      * Instruction visitor class for counting registers used.
311      */
312     private static class RegCountVisitor
313             implements Insn.Visitor {
314         /** {@code >= 0;} register count in-progress */
315         private int regCount;
316 
317         /**
318          * Constructs an instance.
319          */
RegCountVisitor()320         public RegCountVisitor() {
321             regCount = 0;
322         }
323 
324         /**
325          * Gets the register count.
326          *
327          * @return {@code >= 0;} the count
328          */
getRegCount()329         public int getRegCount() {
330             return regCount;
331         }
332 
333         /** {@inheritDoc} */
334         @Override
visitPlainInsn(PlainInsn insn)335         public void visitPlainInsn(PlainInsn insn) {
336             visit(insn);
337         }
338 
339         /** {@inheritDoc} */
340         @Override
visitPlainCstInsn(PlainCstInsn insn)341         public void visitPlainCstInsn(PlainCstInsn insn) {
342             visit(insn);
343         }
344 
345         /** {@inheritDoc} */
346         @Override
visitSwitchInsn(SwitchInsn insn)347         public void visitSwitchInsn(SwitchInsn insn) {
348             visit(insn);
349         }
350 
351         /** {@inheritDoc} */
352         @Override
visitThrowingCstInsn(ThrowingCstInsn insn)353         public void visitThrowingCstInsn(ThrowingCstInsn insn) {
354             visit(insn);
355         }
356 
357         /** {@inheritDoc} */
358         @Override
visitThrowingInsn(ThrowingInsn insn)359         public void visitThrowingInsn(ThrowingInsn insn) {
360             visit(insn);
361         }
362 
363         /** {@inheritDoc} */
364         @Override
visitFillArrayDataInsn(FillArrayDataInsn insn)365         public void visitFillArrayDataInsn(FillArrayDataInsn insn) {
366             visit(insn);
367         }
368 
369         /** {@inheritDoc} */
370         @Override
visitInvokePolymorphicInsn(InvokePolymorphicInsn insn)371         public void visitInvokePolymorphicInsn(InvokePolymorphicInsn insn) {
372             visit(insn);
373         }
374 
375         /**
376          * Helper for all the {@code visit*} methods.
377          *
378          * @param insn {@code non-null;} instruction being visited
379          */
visit(Insn insn)380         private void visit(Insn insn) {
381             RegisterSpec result = insn.getResult();
382 
383             if (result != null) {
384                 processReg(result);
385             }
386 
387             RegisterSpecList sources = insn.getSources();
388             int sz = sources.size();
389 
390             for (int i = 0; i < sz; i++) {
391                 processReg(sources.get(i));
392             }
393         }
394 
395         /**
396          * Processes the given register spec.
397          *
398          * @param spec {@code non-null;} the register spec
399          */
processReg(RegisterSpec spec)400         private void processReg(RegisterSpec spec) {
401             int reg = spec.getNextReg();
402 
403             if (reg > regCount) {
404                 regCount = reg;
405             }
406         }
407     }
408 }
409