• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4 
5 package com.android.tools.r8.ir.code;
6 
7 import com.android.tools.r8.graph.DexType;
8 import java.util.ArrayList;
9 import java.util.List;
10 import java.util.ListIterator;
11 import java.util.function.Predicate;
12 
13 public interface InstructionListIterator extends ListIterator<Instruction> {
14 
15   /**
16    * Peek the previous instruction.
17    *
18    * @return what will be returned by calling {@link #previous}. If there is no previous instruction
19    * <code>null</code> is returned.
20    */
peekPrevious()21   default Instruction peekPrevious() {
22     Instruction previous = null;
23     if (hasPrevious()) {
24       previous = previous();
25       next();
26     }
27     return previous;
28   }
29 
30   /**
31    * Peek the next instruction.
32    *
33    * @return what will be returned by calling {@link #next}. If there is no next instruction
34    * <code>null</code> is returned.
35    */
peekNext()36   default Instruction peekNext() {
37     Instruction next = null;
38     if (hasNext()) {
39       next = next();
40       previous();
41     }
42     return next;
43   }
44 
45   /**
46    * Continue to call {@link #next} while {@code predicate} tests {@code false}.
47    *
48    * @returns the instruction that matched the predicate or {@code null} if all instructions fails
49    * the predicate test
50    */
nextUntil(Predicate<Instruction> predicate)51   default Instruction nextUntil(Predicate<Instruction> predicate) {
52     while (hasNext()) {
53       Instruction instruction = next();
54       if (predicate.test(instruction)) {
55         return instruction;
56       }
57     }
58     return null;
59   }
60 
61   /**
62    * Remove the current instruction (aka the {@link Instruction} returned by the previous call to
63    * {@link #next}) without updating its def/use chains.
64    * <p>
65    * This is useful for instance when moving an instruction to another block that still dominates
66    * all its uses. In order to do that you would detach the instruction from the original
67    * block and add it to the new block.
68    */
detach()69   void detach();
70 
71   /**
72    * Replace the current instruction (aka the {@link Instruction} returned by the previous call to
73    * {@link #next} with the passed in <code>newInstruction</code>.
74    *
75    * The current instruction will be completely detached from the instruction stream with uses
76    * of its in-values removed.
77    *
78    * If the current instruction produces an out-value the new instruction must also produce
79    * an out-value, and all uses of the current instructions out-value will be replaced by the
80    * new instructions out-value.
81    *
82    * @param newInstruction the instruction to insert instead of the current.
83    */
replaceCurrentInstruction(Instruction newInstruction)84   void replaceCurrentInstruction(Instruction newInstruction);
85 
86   /**
87    * Split the block into two blocks at the point of the {@link ListIterator} cursor. The existing
88    * block will have all the instructions before the cursor, and the new block all the
89    * instructions after the cursor.
90    *
91    * If the current block has catch handlers these catch handlers will be attached to the block
92    * containing the throwing instruction after the split.
93    *
94    * @param code the IR code for the block this iterator originates from.
95    * @param blockIterator basic block iterator used to iterate the blocks. This must be positioned
96    * just after the block for which this is the instruction iterator. After this method returns it
97    * will be positioned just after the basic block returned.
98    * @return Returns the new block with the instructions after the cursor.
99    */
split(IRCode code, ListIterator<BasicBlock> blockIterator)100   BasicBlock split(IRCode code, ListIterator<BasicBlock> blockIterator);
101 
102 
split(IRCode code)103   default BasicBlock split(IRCode code) {
104     return split(code, null);
105   }
106 
107   /**
108    * Split the block into three blocks. The first split is at the point of the {@link ListIterator}
109    * cursor and the second split is <code>instructions</code> after the cursor. The existing
110    * block will have all the instructions before the cursor, and the two new blocks all the
111    * instructions after the cursor.
112    *
113    * If the current block have catch handlers these catch handlers will be attached to the block
114    * containing the throwing instruction after the split.
115    *
116    * @param instructions the number of instructions to include in the second block.
117    * @param code the IR code for the block this iterator originates from.
118    * @param blockIterator basic block iterator used to iterate the blocks. This must be positioned
119    * just after the block for this is the instruction iterator. After this method returns it will be
120    * positioned just after the second block inserted. That is after the successor of the block
121    * returned.
122    * @return Returns the new block with the instructions right after the cursor.
123    */
124   // TODO(sgjesse): Refactor to avoid the need for passing code and blockIterator.
split(int instructions, IRCode code, ListIterator<BasicBlock> blockIterator)125   BasicBlock split(int instructions, IRCode code, ListIterator<BasicBlock> blockIterator);
126 
127   /**
128    * See {@link #split(int, IRCode, ListIterator)}.
129    */
split(int instructions, IRCode code)130   default BasicBlock split(int instructions, IRCode code) {
131     return split(instructions, code, null);
132   }
133 
134   /**
135    * Inline the code in {@code inlinee} into {@code code}, replacing the invoke instruction at the
136    * position after the cursor.
137    *
138    * The instruction at the position after cursor must be an invoke that matches the signature for
139    * the code in {@code inlinee}.
140    *
141    * With one exception (see below) both the calling code and the inlinee can have catch handlers.
142    *
143    * <strong>EXCEPTION:</strong> If the invoke instruction is covered by catch handlers, and the
144    * code for {@code inlinee} always throws (does not have a normal return) inlining is currently
145    * <strong>NOT</strong> supported.
146    *
147    * @param code the IR code for the block this iterator originates from.
148    * @param inlinee the IR code for the block this iterator originates from.
149    * @param blockIterator basic block iterator used to iterate the blocks. This must be positioned
150    * just after the block for which this is the instruction iterator. After this method returns it
151    * will be positioned just after the basic block returned.
152    * @param blocksToRemove list passed where blocks that where detached from the graph, but not
153    * removed are added. When inlining an inlinee that always throws blocks in the <code>code</code>
154    * can be detached, and not simply removed unsing the passed <code>blockIterator</code>. When
155    * iterating using <code>blockIterator</code> after then method returns the blocks in this list
156    * must be skipped when iterating with the active <code>blockIterator</code> and ultimately
157    * removed.
158    * @param downcast tells the inliner to issue a check cast opertion.
159    * @return the basic block with the instructions right after the inlining. This can be a block
160    * which can also be in the <code>blocksToRemove</code> list.
161    */
162   // TODO(sgjesse): Refactor to avoid the need for passing code.
163   // TODO(sgjesse): Refactor to avoid the need for passing blocksToRemove.
164   // TODO(sgjesse): Maybe don't return a BasicBlock, as it can be in blocksToRemove.
165   // TODO(sgjesse): Maybe find a better place for this method.
166   // TODO(sgjesse): Support inlinee with throwing instructions for invokes with existing handlers.
inlineInvoke(IRCode code, IRCode inlinee, ListIterator<BasicBlock> blockIterator, List<BasicBlock> blocksToRemove, DexType downcast)167   BasicBlock inlineInvoke(IRCode code, IRCode inlinee, ListIterator<BasicBlock> blockIterator,
168       List<BasicBlock> blocksToRemove, DexType downcast);
169 
170   /**
171    * See {@link #inlineInvoke(IRCode, IRCode, ListIterator<BasicBlock>, List<BasicBlock>, DexType)}.
172    */
inlineInvoke(IRCode code, IRCode inlinee)173   default BasicBlock inlineInvoke(IRCode code, IRCode inlinee) {
174     List<BasicBlock> blocksToRemove = new ArrayList<>();
175     BasicBlock result = inlineInvoke(code, inlinee, null, blocksToRemove, null);
176     code.removeBlocks(blocksToRemove);
177     return result;
178   }
179 }
180