• 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.TypeList;
20 import com.android.dx.util.Hex;
21 import com.android.dx.util.IntList;
22 import com.android.dx.util.LabeledItem;
23 
24 /**
25  * Basic block of register-based instructions.
26  */
27 public final class BasicBlock implements LabeledItem {
28     /** {@code >= 0;} target label for this block */
29     private final int label;
30 
31     /** {@code non-null;} list of instructions in this block */
32     private final InsnList insns;
33 
34     /**
35      * {@code non-null;} full list of successors that this block may
36      * branch to
37      */
38     private final IntList successors;
39 
40     /**
41      * {@code >= -1;} the primary / standard-flow / "default" successor, or
42      * {@code -1} if this block has no successors (that is, it
43      * exits the function/method)
44      */
45     private final int primarySuccessor;
46 
47     /**
48      * Constructs an instance. The predecessor set is set to {@code null}.
49      *
50      * @param label {@code >= 0;} target label for this block
51      * @param insns {@code non-null;} list of instructions in this block
52      * @param successors {@code non-null;} full list of successors that this
53      * block may branch to
54      * @param primarySuccessor {@code >= -1;} the primary / standard-flow /
55      * "default" successor, or {@code -1} if this block has no
56      * successors (that is, it exits the function/method or is an
57      * unconditional throw)
58      */
BasicBlock(int label, InsnList insns, IntList successors, int primarySuccessor)59     public BasicBlock(int label, InsnList insns, IntList successors,
60                       int primarySuccessor) {
61         if (label < 0) {
62             throw new IllegalArgumentException("label < 0");
63         }
64 
65         try {
66             insns.throwIfMutable();
67         } catch (NullPointerException ex) {
68             // Elucidate exception.
69             throw new NullPointerException("insns == null");
70         }
71 
72         int sz = insns.size();
73 
74         if (sz == 0) {
75             throw new IllegalArgumentException("insns.size() == 0");
76         }
77 
78         for (int i = sz - 2; i >= 0; i--) {
79             Rop one = insns.get(i).getOpcode();
80             if (one.getBranchingness() != Rop.BRANCH_NONE) {
81                 throw new IllegalArgumentException("insns[" + i + "] is a " +
82                                                    "branch or can throw");
83             }
84         }
85 
86         Insn lastInsn = insns.get(sz - 1);
87         if (lastInsn.getOpcode().getBranchingness() == Rop.BRANCH_NONE) {
88             throw new IllegalArgumentException("insns does not end with " +
89                                                "a branch or throwing " +
90                                                "instruction");
91         }
92 
93         try {
94             successors.throwIfMutable();
95         } catch (NullPointerException ex) {
96             // Elucidate exception.
97             throw new NullPointerException("successors == null");
98         }
99 
100         if (primarySuccessor < -1) {
101             throw new IllegalArgumentException("primarySuccessor < -1");
102         }
103 
104         if (primarySuccessor >= 0 && !successors.contains(primarySuccessor)) {
105             throw new IllegalArgumentException(
106                     "primarySuccessor " + primarySuccessor + " not in successors " + successors);
107         }
108 
109         this.label = label;
110         this.insns = insns;
111         this.successors = successors;
112         this.primarySuccessor = primarySuccessor;
113     }
114 
115     /**
116      * {@inheritDoc}
117      *
118      * Instances of this class compare by identity. That is,
119      * {@code x.equals(y)} is only true if {@code x == y}.
120      */
121     @Override
equals(Object other)122     public boolean equals(Object other) {
123         return (this == other);
124     }
125 
126     /**
127      * {@inheritDoc}
128      *
129      * Return the identity hashcode of this instance. This is proper,
130      * since instances of this class compare by identity (see {@link #equals}).
131      */
132     @Override
hashCode()133     public int hashCode() {
134         return System.identityHashCode(this);
135     }
136 
137     /**
138      * Gets the target label of this block.
139      *
140      * @return {@code >= 0;} the label
141      */
getLabel()142     public int getLabel() {
143         return label;
144     }
145 
146     /**
147      * Gets the list of instructions inside this block.
148      *
149      * @return {@code non-null;} the instruction list
150      */
getInsns()151     public InsnList getInsns() {
152         return insns;
153     }
154 
155     /**
156      * Gets the list of successors that this block may branch to.
157      *
158      * @return {@code non-null;} the successors list
159      */
getSuccessors()160     public IntList getSuccessors() {
161         return successors;
162     }
163 
164     /**
165      * Gets the primary successor of this block.
166      *
167      * @return {@code >= -1;} the primary successor, or {@code -1} if this
168      * block has no successors at all
169      */
getPrimarySuccessor()170     public int getPrimarySuccessor() {
171         return primarySuccessor;
172     }
173 
174     /**
175      * Gets the secondary successor of this block. It is only valid to call
176      * this method on blocks that have exactly two successors.
177      *
178      * @return {@code >= 0;} the secondary successor
179      */
getSecondarySuccessor()180     public int getSecondarySuccessor() {
181         if (successors.size() != 2) {
182             throw new UnsupportedOperationException(
183                     "block doesn't have exactly two successors");
184         }
185 
186         int succ = successors.get(0);
187         if (succ == primarySuccessor) {
188             succ = successors.get(1);
189         }
190 
191         return succ;
192     }
193 
194     /**
195      * Gets the first instruction of this block. This is just a
196      * convenient shorthand for {@code getInsns().get(0)}.
197      *
198      * @return {@code non-null;} the first instruction
199      */
getFirstInsn()200     public Insn getFirstInsn() {
201         return insns.get(0);
202     }
203 
204     /**
205      * Gets the last instruction of this block. This is just a
206      * convenient shorthand for {@code getInsns().getLast()}.
207      *
208      * @return {@code non-null;} the last instruction
209      */
getLastInsn()210     public Insn getLastInsn() {
211         return insns.getLast();
212     }
213 
214     /**
215      * Returns whether this block might throw an exception. This is
216      * just a convenient shorthand for {@code getLastInsn().canThrow()}.
217      *
218      * @return {@code true} iff this block might throw an
219      * exception
220      */
canThrow()221     public boolean canThrow() {
222         return insns.getLast().canThrow();
223     }
224 
225     /**
226      * Returns whether this block has any associated exception handlers.
227      * This is just a shorthand for inspecting the last instruction in
228      * the block to see if it could throw, and if so, whether it in fact
229      * has any associated handlers.
230      *
231      * @return {@code true} iff this block has any associated
232      * exception handlers
233      */
hasExceptionHandlers()234     public boolean hasExceptionHandlers() {
235         Insn lastInsn = insns.getLast();
236         return lastInsn.getCatches().size() != 0;
237     }
238 
239     /**
240      * Returns the exception handler types associated with this block,
241      * if any. This is just a shorthand for inspecting the last
242      * instruction in the block to see if it could throw, and if so,
243      * grabbing the catch list out of it. If not, this returns an
244      * empty list (not {@code null}).
245      *
246      * @return {@code non-null;} the exception handler types associated with
247      * this block
248      */
getExceptionHandlerTypes()249     public TypeList getExceptionHandlerTypes() {
250         Insn lastInsn = insns.getLast();
251         return lastInsn.getCatches();
252     }
253 
254     /**
255      * Returns an instance that is identical to this one, except that
256      * the registers in each instruction are offset by the given
257      * amount.
258      *
259      * @param delta the amount to offset register numbers by
260      * @return {@code non-null;} an appropriately-constructed instance
261      */
withRegisterOffset(int delta)262     public BasicBlock withRegisterOffset(int delta) {
263         return new BasicBlock(label, insns.withRegisterOffset(delta),
264                               successors, primarySuccessor);
265     }
266 
toString()267     public String toString() {
268         return '{' + Hex.u2(label) + '}';
269     }
270 
271     /**
272      * BasicBlock visitor interface
273      */
274     public interface Visitor {
275         /**
276          * Visits a basic block
277          * @param b block visited
278          */
visitBlock(BasicBlock b)279         public void visitBlock (BasicBlock b);
280     }
281 }
282