blob: 84eaee6d498d5f508a3c987a8589a6414a908576 [file] [log] [blame]
// Copyright (c) 2022, 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.lightir;
import it.unimi.dsi.fastutil.bytes.ByteIterator;
import java.util.Iterator;
/**
* Basic iterator over the light IR.
*
* <p>This iterator is internally a zero-allocation parser with the "elements" as a view onto the
* current state.
*/
public class LirIterator implements Iterator<LirInstructionView>, LirInstructionView {
private final ByteIterator iterator;
// State of the byte offsets into the iterator.
private int currentByteIndex = 0;
private int endOfCurrentInstruction = 0;
// State of the instruction interpretation.
private int currentInstructionIndex = -1;
private int currentOpcode = -1;
public LirIterator(ByteIterator iterator) {
this.iterator = iterator;
}
private void skipRemainingOperands() {
if (hasMoreOperands()) {
skip(getRemainingOperandSizeInBytes());
}
}
@Override
public boolean hasNext() {
skipRemainingOperands();
return iterator.hasNext();
}
@Override
public LirInstructionView next() {
skipRemainingOperands();
++currentInstructionIndex;
currentOpcode = u1();
if (LirOpcodes.isOneByteInstruction(currentOpcode)) {
endOfCurrentInstruction = currentByteIndex;
} else {
// Any instruction that is not a single byte has a two-byte header. The second byte is the
// size of the variable width operand payload.
int operandSize = u1();
endOfCurrentInstruction = currentByteIndex + operandSize;
}
return this;
}
@Override
public void accept(LirInstructionCallback eventCallback) {
eventCallback.onInstructionView(this);
}
@Override
public int getInstructionIndex() {
return currentInstructionIndex;
}
@Override
public int getOpcode() {
return currentOpcode;
}
@Override
public int getRemainingOperandSizeInBytes() {
return endOfCurrentInstruction - currentByteIndex;
}
@Override
public boolean hasMoreOperands() {
return currentByteIndex < endOfCurrentInstruction;
}
@Override
public int getNextIntegerOperand() {
assert hasMoreOperands();
return u4();
}
@Override
public long getNextLongOperand() {
assert hasMoreOperands();
return u8();
}
@Override
public int getNextConstantOperand() {
return getNextIntegerOperand();
}
@Override
public int getNextValueOperand() {
return getNextIntegerOperand();
}
@Override
public int getNextBlockOperand() {
return getNextIntegerOperand();
}
private void skip(int i) {
currentByteIndex += i;
iterator.skip(i);
}
private int u1() {
++currentByteIndex;
return ByteUtils.fromU1(iterator.nextByte());
}
private int u4() {
currentByteIndex += 4;
return ByteUtils.readEncodedInt(iterator);
}
private long u8() {
currentByteIndex += 8;
return ByteUtils.readEncodedLong(iterator);
}
}