| // Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| package com.android.tools.r8.ir.code; |
| |
| import com.android.tools.r8.graph.DexType; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.ListIterator; |
| import java.util.function.Predicate; |
| |
| public interface InstructionListIterator extends ListIterator<Instruction>, |
| NextUntilIterator<Instruction> { |
| |
| /** |
| * Peek the previous instruction. |
| * |
| * @return what will be returned by calling {@link #previous}. If there is no previous instruction |
| * <code>null</code> is returned. |
| */ |
| default Instruction peekPrevious() { |
| Instruction previous = null; |
| if (hasPrevious()) { |
| previous = previous(); |
| next(); |
| } |
| return previous; |
| } |
| |
| /** |
| * Peek the next instruction. |
| * |
| * @return what will be returned by calling {@link #next}. If there is no next instruction |
| * <code>null</code> is returned. |
| */ |
| default Instruction peekNext() { |
| Instruction next = null; |
| if (hasNext()) { |
| next = next(); |
| previous(); |
| } |
| return next; |
| } |
| |
| /** |
| * Continue to call {@link #next} while {@code predicate} tests {@code false}. |
| * |
| * @return the instruction that matched the predicate or {@code null} if all instructions fails |
| * the predicate test |
| */ |
| default Instruction nextUntil(Predicate<Instruction> predicate) { |
| while (hasNext()) { |
| Instruction instruction = next(); |
| if (predicate.test(instruction)) { |
| return instruction; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Remove the current instruction (aka the {@link Instruction} returned by the previous call to |
| * {@link #next}) without updating its def/use chains. |
| * <p> |
| * This is useful for instance when moving an instruction to another block that still dominates |
| * all its uses. In order to do that you would detach the instruction from the original |
| * block and add it to the new block. |
| */ |
| void detach(); |
| |
| /** |
| * Replace the current instruction (aka the {@link Instruction} returned by the previous call to |
| * {@link #next} with the passed in <code>newInstruction</code>. |
| * |
| * The current instruction will be completely detached from the instruction stream with uses |
| * of its in-values removed. |
| * |
| * If the current instruction produces an out-value the new instruction must also produce |
| * an out-value, and all uses of the current instructions out-value will be replaced by the |
| * new instructions out-value. |
| * |
| * @param newInstruction the instruction to insert instead of the current. |
| */ |
| void replaceCurrentInstruction(Instruction newInstruction); |
| |
| /** |
| * Split the block into two blocks at the point of the {@link ListIterator} cursor. The existing |
| * block will have all the instructions before the cursor, and the new block all the |
| * instructions after the cursor. |
| * |
| * If the current block has catch handlers these catch handlers will be attached to the block |
| * containing the throwing instruction after the split. |
| * |
| * @param code the IR code for the block this iterator originates from. |
| * @param blockIterator basic block iterator used to iterate the blocks. This must be positioned |
| * just after the block for which this is the instruction iterator. After this method returns it |
| * will be positioned just after the basic block returned. |
| * @return Returns the new block with the instructions after the cursor. |
| */ |
| BasicBlock split(IRCode code, ListIterator<BasicBlock> blockIterator); |
| |
| |
| default BasicBlock split(IRCode code) { |
| return split(code, null); |
| } |
| |
| /** |
| * Split the block into three blocks. The first split is at the point of the {@link ListIterator} |
| * cursor and the second split is <code>instructions</code> after the cursor. The existing |
| * block will have all the instructions before the cursor, and the two new blocks all the |
| * instructions after the cursor. |
| * |
| * If the current block have catch handlers these catch handlers will be attached to the block |
| * containing the throwing instruction after the split. |
| * |
| * @param instructions the number of instructions to include in the second block. |
| * @param code the IR code for the block this iterator originates from. |
| * @param blockIterator basic block iterator used to iterate the blocks. This must be positioned |
| * just after the block for this is the instruction iterator. After this method returns it will be |
| * positioned just after the second block inserted. That is after the successor of the block |
| * returned. |
| * @return Returns the new block with the instructions right after the cursor. |
| */ |
| // TODO(sgjesse): Refactor to avoid the need for passing code and blockIterator. |
| BasicBlock split(int instructions, IRCode code, ListIterator<BasicBlock> blockIterator); |
| |
| /** |
| * See {@link #split(int, IRCode, ListIterator)}. |
| */ |
| default BasicBlock split(int instructions, IRCode code) { |
| return split(instructions, code, null); |
| } |
| |
| /** |
| * Inline the code in {@code inlinee} into {@code code}, replacing the invoke instruction at the |
| * position after the cursor. |
| * |
| * The instruction at the position after cursor must be an invoke that matches the signature for |
| * the code in {@code inlinee}. |
| * |
| * With one exception (see below) both the calling code and the inlinee can have catch handlers. |
| * |
| * <strong>EXCEPTION:</strong> If the invoke instruction is covered by catch handlers, and the |
| * code for {@code inlinee} always throws (does not have a normal return) inlining is currently |
| * <strong>NOT</strong> supported. |
| * |
| * @param code the IR code for the block this iterator originates from. |
| * @param inlinee the IR code for the block this iterator originates from. |
| * @param blockIterator basic block iterator used to iterate the blocks. This must be positioned |
| * just after the block for which this is the instruction iterator. After this method returns it |
| * will be positioned just after the basic block returned. |
| * @param blocksToRemove list passed where blocks that where detached from the graph, but not |
| * removed are added. When inlining an inlinee that always throws blocks in the <code>code</code> |
| * can be detached, and not simply removed unsing the passed <code>blockIterator</code>. When |
| * iterating using <code>blockIterator</code> after then method returns the blocks in this list |
| * must be skipped when iterating with the active <code>blockIterator</code> and ultimately |
| * removed. |
| * @param downcast tells the inliner to issue a check cast opertion. |
| * @return the basic block with the instructions right after the inlining. This can be a block |
| * which can also be in the <code>blocksToRemove</code> list. |
| */ |
| // TODO(sgjesse): Refactor to avoid the need for passing code. |
| // TODO(sgjesse): Refactor to avoid the need for passing blocksToRemove. |
| // TODO(sgjesse): Maybe don't return a BasicBlock, as it can be in blocksToRemove. |
| // TODO(sgjesse): Maybe find a better place for this method. |
| // TODO(sgjesse): Support inlinee with throwing instructions for invokes with existing handlers. |
| BasicBlock inlineInvoke(IRCode code, IRCode inlinee, ListIterator<BasicBlock> blockIterator, |
| List<BasicBlock> blocksToRemove, DexType downcast); |
| |
| /** |
| * See {@link #inlineInvoke(IRCode, IRCode, ListIterator, List, DexType)}. |
| */ |
| default BasicBlock inlineInvoke(IRCode code, IRCode inlinee) { |
| List<BasicBlock> blocksToRemove = new ArrayList<>(); |
| BasicBlock result = inlineInvoke(code, inlinee, null, blocksToRemove, null); |
| code.removeBlocks(blocksToRemove); |
| return result; |
| } |
| } |