• 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.ssa;
18 
19 import com.android.dx.rop.code.RegisterSpec;
20 import com.android.dx.rop.code.RopMethod;
21 import com.android.dx.util.IntIterator;
22 
23 import java.util.ArrayList;
24 import java.util.BitSet;
25 
26 /**
27  * Converts ROP methods to SSA Methods
28  */
29 public class SsaConverter {
30     public static final boolean DEBUG = false;
31 
32     /**
33      * Returns an SSA representation, edge-split and with phi
34      * functions placed.
35      *
36      * @param rmeth input
37      * @param paramWidth the total width, in register-units, of the method's
38      * parameters
39      * @param isStatic {@code true} if this method has no {@code this}
40      * pointer argument
41      * @return output in SSA form
42      */
convertToSsaMethod(RopMethod rmeth, int paramWidth, boolean isStatic)43     public static SsaMethod convertToSsaMethod(RopMethod rmeth,
44             int paramWidth, boolean isStatic) {
45         SsaMethod result
46             = SsaMethod.newFromRopMethod(rmeth, paramWidth, isStatic);
47 
48         edgeSplit(result);
49 
50         LocalVariableInfo localInfo = LocalVariableExtractor.extract(result);
51 
52         placePhiFunctions(result, localInfo, 0);
53         new SsaRenamer(result).run();
54 
55         /*
56          * The exit block, added here, is not considered for edge splitting
57          * or phi placement since no actual control flows to it.
58          */
59         result.makeExitBlock();
60 
61         return result;
62     }
63 
64     /**
65      * Updates an SSA representation, placing phi functions and renaming all
66      * registers above a certain threshold number.
67      *
68      * @param ssaMeth input
69      * @param threshold registers below this number are unchanged
70      */
updateSsaMethod(SsaMethod ssaMeth, int threshold)71     public static void updateSsaMethod(SsaMethod ssaMeth, int threshold) {
72         LocalVariableInfo localInfo = LocalVariableExtractor.extract(ssaMeth);
73         placePhiFunctions(ssaMeth, localInfo, threshold);
74         new SsaRenamer(ssaMeth, threshold).run();
75     }
76 
77     /**
78      * Returns an SSA represention with only the edge-splitter run.
79      *
80      * @param rmeth method to process
81      * @param paramWidth width of all arguments in the method
82      * @param isStatic {@code true} if this method has no {@code this}
83      * pointer argument
84      * @return an SSA represention with only the edge-splitter run
85      */
testEdgeSplit(RopMethod rmeth, int paramWidth, boolean isStatic)86     public static SsaMethod testEdgeSplit (RopMethod rmeth, int paramWidth,
87             boolean isStatic) {
88         SsaMethod result;
89 
90         result = SsaMethod.newFromRopMethod(rmeth, paramWidth, isStatic);
91 
92         edgeSplit(result);
93         return result;
94     }
95 
96     /**
97      * Returns an SSA represention with only the steps through the
98      * phi placement run.
99      *
100      * @param rmeth method to process
101      * @param paramWidth width of all arguments in the method
102      * @param isStatic {@code true} if this method has no {@code this}
103      * pointer argument
104      * @return an SSA represention with only the edge-splitter run
105      */
testPhiPlacement(RopMethod rmeth, int paramWidth, boolean isStatic)106     public static SsaMethod testPhiPlacement (RopMethod rmeth, int paramWidth,
107             boolean isStatic) {
108         SsaMethod result;
109 
110         result = SsaMethod.newFromRopMethod(rmeth, paramWidth, isStatic);
111 
112         edgeSplit(result);
113 
114         LocalVariableInfo localInfo = LocalVariableExtractor.extract(result);
115 
116         placePhiFunctions(result, localInfo, 0);
117         return result;
118     }
119 
120     /**
121      * See Appel section 19.1:
122      *
123      * Converts CFG into "edge-split" form, such that each node either a
124      * unique successor or unique predecessor.<p>
125      *
126      * In addition, the SSA form we use enforces a further constraint,
127      * requiring each block with a final instruction that returns a
128      * value to have a primary successor that has no other
129      * predecessor. This ensures move statements can always be
130      * inserted correctly when phi statements are removed.
131      *
132      * @param result method to process
133      */
edgeSplit(SsaMethod result)134     private static void edgeSplit(SsaMethod result) {
135         edgeSplitPredecessors(result);
136         edgeSplitMoveExceptionsAndResults(result);
137         edgeSplitSuccessors(result);
138     }
139 
140     /**
141      * Inserts Z nodes as new predecessors for every node that has multiple
142      * successors and multiple predecessors.
143      *
144      * @param result {@code non-null;} method to process
145      */
edgeSplitPredecessors(SsaMethod result)146     private static void edgeSplitPredecessors(SsaMethod result) {
147         ArrayList<SsaBasicBlock> blocks = result.getBlocks();
148 
149         /*
150          * New blocks are added to the end of the block list during
151          * this iteration.
152          */
153         for (int i = blocks.size() - 1; i >= 0; i-- ) {
154             SsaBasicBlock block = blocks.get(i);
155             if (nodeNeedsUniquePredecessor(block)) {
156                 block.insertNewPredecessor();
157             }
158         }
159     }
160 
161     /**
162      * @param block {@code non-null;} block in question
163      * @return {@code true} if this node needs to have a unique
164      * predecessor created for it
165      */
nodeNeedsUniquePredecessor(SsaBasicBlock block)166     private static boolean nodeNeedsUniquePredecessor(SsaBasicBlock block) {
167         /*
168          * Any block with that has both multiple successors and multiple
169          * predecessors needs a new predecessor node.
170          */
171 
172         int countPredecessors = block.getPredecessors().cardinality();
173         int countSuccessors = block.getSuccessors().cardinality();
174 
175         return  (countPredecessors > 1 && countSuccessors > 1);
176     }
177 
178     /**
179      * In ROP form, move-exception must occur as the first insn in a block
180      * immediately succeeding the insn that could thrown an exception.
181      * We may need room to insert move insns later, so make sure to split
182      * any block that starts with a move-exception such that there is a
183      * unique move-exception block for each predecessor.
184      *
185      * @param ssaMeth method to process
186      */
edgeSplitMoveExceptionsAndResults(SsaMethod ssaMeth)187     private static void edgeSplitMoveExceptionsAndResults(SsaMethod ssaMeth) {
188         ArrayList<SsaBasicBlock> blocks = ssaMeth.getBlocks();
189 
190         /*
191          * New blocks are added to the end of the block list during
192          * this iteration.
193          */
194         for (int i = blocks.size() - 1; i >= 0; i-- ) {
195             SsaBasicBlock block = blocks.get(i);
196 
197             /*
198              * Any block that starts with a move-exception and has more than
199              * one predecessor...
200              */
201             if (!block.isExitBlock()
202                     && block.getPredecessors().cardinality() > 1
203                     && block.getInsns().get(0).isMoveException()) {
204 
205                 // block.getPredecessors() is changed in the loop below.
206                 BitSet preds = (BitSet)block.getPredecessors().clone();
207                 for (int j = preds.nextSetBit(0); j >= 0;
208                      j = preds.nextSetBit(j + 1)) {
209                     SsaBasicBlock predecessor = blocks.get(j);
210                     SsaBasicBlock zNode
211                         = predecessor.insertNewSuccessor(block);
212 
213                     /*
214                      * Make sure to place the move-exception as the
215                      * first insn.
216                      */
217                     zNode.getInsns().add(0, block.getInsns().get(0).clone());
218                 }
219 
220                 // Remove the move-exception from the original block.
221                 block.getInsns().remove(0);
222             }
223         }
224     }
225 
226     /**
227      * Inserts Z nodes for every node that needs a new
228      * successor.
229      *
230      * @param result {@code non-null;} method to process
231      */
edgeSplitSuccessors(SsaMethod result)232     private static void edgeSplitSuccessors(SsaMethod result) {
233         ArrayList<SsaBasicBlock> blocks = result.getBlocks();
234 
235         /*
236          * New blocks are added to the end of the block list during
237          * this iteration.
238          */
239         for (int i = blocks.size() - 1; i >= 0; i-- ) {
240             SsaBasicBlock block = blocks.get(i);
241 
242             // Successors list is modified in loop below.
243             BitSet successors = (BitSet)block.getSuccessors().clone();
244             for (int j = successors.nextSetBit(0);
245                  j >= 0; j = successors.nextSetBit(j+1)) {
246 
247                 SsaBasicBlock succ = blocks.get(j);
248 
249                 if (needsNewSuccessor(block, succ)) {
250                     block.insertNewSuccessor(succ);
251                 }
252             }
253         }
254     }
255 
256     /**
257      * Returns {@code true} if block and successor need a Z-node
258      * between them. Presently, this is {@code true} if the final
259      * instruction has any sources or results and the current
260      * successor block has more than one predecessor.
261      *
262      * @param block predecessor node
263      * @param succ successor node
264      * @return {@code true} if a Z node is needed
265      */
needsNewSuccessor(SsaBasicBlock block, SsaBasicBlock succ)266     private static boolean needsNewSuccessor(SsaBasicBlock block,
267             SsaBasicBlock succ) {
268         ArrayList<SsaInsn> insns = block.getInsns();
269         SsaInsn lastInsn = insns.get(insns.size() - 1);
270 
271         return ((lastInsn.getResult() != null)
272                     || (lastInsn.getSources().size() > 0))
273                 && succ.getPredecessors().cardinality() > 1;
274     }
275 
276     /**
277      * See Appel algorithm 19.6:
278      *
279      * Place Phi functions in appropriate locations.
280      *
281      * @param ssaMeth {@code non-null;} method to process.
282      * Modifications are made in-place.
283      * @param localInfo {@code non-null;} local variable info, used
284      * when placing phis
285      * @param threshold registers below this number are ignored
286      */
placePhiFunctions(SsaMethod ssaMeth, LocalVariableInfo localInfo, int threshold)287     private static void placePhiFunctions (SsaMethod ssaMeth,
288             LocalVariableInfo localInfo, int threshold) {
289         ArrayList<SsaBasicBlock> ssaBlocks;
290         int regCount;
291         int blockCount;
292 
293         ssaBlocks = ssaMeth.getBlocks();
294         blockCount = ssaBlocks.size();
295         regCount = ssaMeth.getRegCount() - threshold;
296 
297         DomFront df = new DomFront(ssaMeth);
298         DomFront.DomInfo[] domInfos = df.run();
299 
300         // Bit set of registers vs block index "definition sites"
301         BitSet[] defsites = new BitSet[regCount];
302 
303         // Bit set of registers vs block index "phi placement sites"
304         BitSet[] phisites = new BitSet[regCount];
305 
306         for (int i = 0; i < regCount; i++) {
307             defsites[i] = new BitSet(blockCount);
308             phisites[i] = new BitSet(blockCount);
309         }
310 
311         /*
312          * For each register, build a set of all basic blocks where
313          * containing an assignment to that register.
314          */
315         for (int bi = 0, s = ssaBlocks.size(); bi < s; bi++) {
316             SsaBasicBlock b = ssaBlocks.get(bi);
317 
318             for (SsaInsn insn : b.getInsns()) {
319                 RegisterSpec rs = insn.getResult();
320 
321                 if (rs != null && rs.getReg() - threshold >= 0) {
322                     defsites[rs.getReg() - threshold].set(bi);
323                 }
324             }
325         }
326 
327         if (DEBUG) {
328             System.out.println("defsites");
329 
330             for (int i = 0; i < regCount; i++) {
331                 StringBuilder sb = new StringBuilder();
332                 sb.append('v').append(i).append(": ");
333                 sb.append(defsites[i].toString());
334                 System.out.println(sb);
335             }
336         }
337 
338         BitSet worklist;
339 
340         /*
341          * For each register, compute all locations for phi placement
342          * based on dominance-frontier algorithm.
343          */
344         for (int reg = 0, s = regCount; reg < s; reg++) {
345             int workBlockIndex;
346 
347             /* Worklist set starts out with each node where reg is assigned. */
348 
349             worklist = (BitSet) (defsites[reg].clone());
350 
351             while (0 <= (workBlockIndex = worklist.nextSetBit(0))) {
352                 worklist.clear(workBlockIndex);
353                 IntIterator dfIterator
354                     = domInfos[workBlockIndex].dominanceFrontiers.iterator();
355 
356                 while (dfIterator.hasNext()) {
357                     int dfBlockIndex = dfIterator.next();
358 
359                     if (!phisites[reg].get(dfBlockIndex)) {
360                         phisites[reg].set(dfBlockIndex);
361 
362                         int tReg = reg + threshold;
363                         RegisterSpec rs
364                             = localInfo.getStarts(dfBlockIndex).get(tReg);
365 
366                         if (rs == null) {
367                             ssaBlocks.get(dfBlockIndex).addPhiInsnForReg(tReg);
368                         } else {
369                             ssaBlocks.get(dfBlockIndex).addPhiInsnForReg(rs);
370                         }
371 
372                         if (!defsites[reg].get(dfBlockIndex)) {
373                             worklist.set(dfBlockIndex);
374                         }
375                     }
376                 }
377             }
378         }
379 
380         if (DEBUG) {
381             System.out.println("phisites");
382 
383             for (int i = 0; i < regCount; i++) {
384                 StringBuilder sb = new StringBuilder();
385                 sb.append('v').append(i).append(": ");
386                 sb.append(phisites[i].toString());
387                 System.out.println(sb);
388             }
389         }
390     }
391 }
392