BasicBlock.java revision 579d7739c53a2707ad711a2d2cae46d7d782f061
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.rop.code;
18
19import com.android.dx.rop.type.TypeList;
20import com.android.dx.util.Hex;
21import com.android.dx.util.IntList;
22import com.android.dx.util.LabeledItem;
23
24/**
25 * Basic block of register-based instructions.
26 */
27public 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     */
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
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
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
262    public BasicBlock withRegisterOffset(int delta) {
263        return new BasicBlock(label, insns.withRegisterOffset(delta),
264                              successors, primarySuccessor);
265    }
266
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         */
279        public void visitBlock (BasicBlock b);
280    }
281}
282