• 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.util.Bits;
20 import com.android.dx.util.Hex;
21 import com.android.dx.util.IntList;
22 
23 /**
24  * All of the parts that make up a method at the rop layer.
25  */
26 public final class RopMethod {
27     /** {@code non-null;} basic block list of the method */
28     private final BasicBlockList blocks;
29 
30     /** {@code >= 0;} label for the block which starts the method */
31     private final int firstLabel;
32 
33     /**
34      * {@code null-ok;} array of predecessors for each block, indexed by block
35      * label
36      */
37     private IntList[] predecessors;
38 
39     /**
40      * {@code null-ok;} the predecessors for the implicit "exit" block, that is
41      * the labels for the blocks that return, if calculated
42      */
43     private IntList exitPredecessors;
44 
45     /**
46      * Constructs an instance.
47      *
48      * @param blocks {@code non-null;} basic block list of the method
49      * @param firstLabel {@code >= 0;} the label of the first block to execute
50      */
RopMethod(BasicBlockList blocks, int firstLabel)51     public RopMethod(BasicBlockList blocks, int firstLabel) {
52         if (blocks == null) {
53             throw new NullPointerException("blocks == null");
54         }
55 
56         if (firstLabel < 0) {
57             throw new IllegalArgumentException("firstLabel < 0");
58         }
59 
60         this.blocks = blocks;
61         this.firstLabel = firstLabel;
62 
63         this.predecessors = null;
64         this.exitPredecessors = null;
65     }
66 
67     /**
68      * Gets the basic block list for this method.
69      *
70      * @return {@code non-null;} the list
71      */
getBlocks()72     public BasicBlockList getBlocks() {
73         return blocks;
74     }
75 
76     /**
77      * Gets the label for the first block in the method that this list
78      * represents.
79      *
80      * @return {@code >= 0;} the first-block label
81      */
getFirstLabel()82     public int getFirstLabel() {
83         return firstLabel;
84     }
85 
86     /**
87      * Gets the predecessors associated with the given block. This throws
88      * an exception if there is no block with the given label.
89      *
90      * @param label {@code >= 0;} the label of the block in question
91      * @return {@code non-null;} the predecessors of that block
92      */
labelToPredecessors(int label)93     public IntList labelToPredecessors(int label) {
94         if (exitPredecessors == null) {
95             calcPredecessors();
96         }
97 
98         IntList result = predecessors[label];
99 
100         if (result == null) {
101             throw new RuntimeException("no such block: " + Hex.u2(label));
102         }
103 
104         return result;
105     }
106 
107     /**
108      * Gets the exit predecessors for this instance.
109      *
110      * @return {@code non-null;} the exit predecessors
111      */
getExitPredecessors()112     public IntList getExitPredecessors() {
113         if (exitPredecessors == null) {
114             calcPredecessors();
115         }
116 
117         return exitPredecessors;
118     }
119 
120 
121     /**
122      * Returns an instance that is identical to this one, except that
123      * the registers in each instruction are offset by the given
124      * amount.
125      *
126      * @param delta the amount to offset register numbers by
127      * @return {@code non-null;} an appropriately-constructed instance
128      */
withRegisterOffset(int delta)129     public RopMethod withRegisterOffset(int delta) {
130         RopMethod result = new RopMethod(blocks.withRegisterOffset(delta),
131                                          firstLabel);
132 
133         if (exitPredecessors != null) {
134             /*
135              * The predecessors have been calculated. It's safe to
136              * inject these into the new instance, since the
137              * transformation being applied doesn't affect the
138              * predecessors.
139              */
140             result.exitPredecessors = exitPredecessors;
141             result.predecessors = predecessors;
142         }
143 
144         return result;
145     }
146 
147     /**
148      * Calculates the predecessor sets for each block as well as for the
149      * exit.
150      */
calcPredecessors()151     private void calcPredecessors() {
152         int maxLabel = blocks.getMaxLabel();
153         IntList[] predecessors = new IntList[maxLabel];
154         IntList exitPredecessors = new IntList(10);
155         int sz = blocks.size();
156 
157         /*
158          * For each block, find its successors, and add the block's label to
159          * the successor's predecessors.
160          */
161         for (int i = 0; i < sz; i++) {
162             BasicBlock one = blocks.get(i);
163             int label = one.getLabel();
164             IntList successors = one.getSuccessors();
165             int ssz = successors.size();
166             if (ssz == 0) {
167                 // This block exits.
168                 exitPredecessors.add(label);
169             } else {
170                 for (int j = 0; j < ssz; j++) {
171                     int succLabel = successors.get(j);
172                     IntList succPreds = predecessors[succLabel];
173                     if (succPreds == null) {
174                         succPreds = new IntList(10);
175                         predecessors[succLabel] = succPreds;
176                     }
177                     succPreds.add(label);
178                 }
179             }
180         }
181 
182         // Sort and immutablize all the predecessor lists.
183         for (int i = 0; i < maxLabel; i++) {
184             IntList preds = predecessors[i];
185             if (preds != null) {
186                 preds.sort();
187                 preds.setImmutable();
188             }
189         }
190 
191         exitPredecessors.sort();
192         exitPredecessors.setImmutable();
193 
194         /*
195          * The start label might not ever have had any predecessors
196          * added to it (probably doesn't, because of how Java gets
197          * translated into rop form). So, check for this and rectify
198          * the situation if required.
199          */
200         if (predecessors[firstLabel] == null) {
201             predecessors[firstLabel] = IntList.EMPTY;
202         }
203 
204         this.predecessors = predecessors;
205         this.exitPredecessors = exitPredecessors;
206     }
207 }
208