package org.graalvm.compiler.lir;
import static org.graalvm.compiler.lir.LIRValueUtil.isVirtualStackSlot;
import static jdk.vm.ci.code.ValueUtil.asAllocatableValue;
import static jdk.vm.ci.code.ValueUtil.isConstantJavaValue;
import static jdk.vm.ci.code.ValueUtil.isIllegalJavaValue;
import static jdk.vm.ci.code.ValueUtil.isVirtualObject;
import java.util.Arrays;
import java.util.EnumSet;
import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
import org.graalvm.compiler.lir.framemap.FrameMap;
import org.graalvm.compiler.lir.util.IndexedValueMap;
import jdk.vm.ci.code.BytecodeFrame;
import jdk.vm.ci.code.DebugInfo;
import jdk.vm.ci.code.StackLockValue;
import jdk.vm.ci.code.VirtualObject;
import jdk.vm.ci.meta.AllocatableValue;
import jdk.vm.ci.meta.JavaValue;
import jdk.vm.ci.meta.Value;
public class LIRFrameState {
public static final LIRFrameState NO_STATE = new LIRFrameState(null, null, null);
public final BytecodeFrame topFrame;
private final VirtualObject[] virtualObjects;
public final LabelRef exceptionEdge;
protected DebugInfo debugInfo;
private IndexedValueMap liveBasePointers;
public LIRFrameState(BytecodeFrame topFrame, VirtualObject[] virtualObjects, LabelRef exceptionEdge) {
this.topFrame = topFrame;
this.virtualObjects = virtualObjects;
this.exceptionEdge = exceptionEdge;
}
public boolean hasDebugInfo() {
return debugInfo != null;
}
public DebugInfo debugInfo() {
assert debugInfo != null : "debug info not allocated yet";
return debugInfo;
}
public void forEachState(LIRInstruction inst, InstructionValueProcedure proc) {
for (BytecodeFrame cur = topFrame; cur != null; cur = cur.caller()) {
processValues(inst, cur.values, proc);
}
if (virtualObjects != null) {
for (VirtualObject obj : virtualObjects) {
processValues(inst, obj.getValues(), proc);
}
}
if (liveBasePointers != null) {
liveBasePointers.forEach(inst, OperandMode.ALIVE, STATE_FLAGS, proc);
}
}
public void visitEachState(LIRInstruction inst, InstructionValueConsumer proc) {
for (BytecodeFrame cur = topFrame; cur != null; cur = cur.caller()) {
visitValues(inst, cur.values, proc);
}
if (virtualObjects != null) {
for (VirtualObject obj : virtualObjects) {
visitValues(inst, obj.getValues(), proc);
}
}
if (liveBasePointers != null) {
liveBasePointers.visitEach(inst, OperandMode.ALIVE, STATE_FLAGS, proc);
}
}
protected static final EnumSet<OperandFlag> STATE_FLAGS = EnumSet.of(OperandFlag.REG, OperandFlag.STACK);
protected void processValues(LIRInstruction inst, JavaValue[] values, InstructionValueProcedure proc) {
for (int i = 0; i < values.length; i++) {
JavaValue value = values[i];
if (isIllegalJavaValue(value)) {
continue;
}
if (value instanceof AllocatableValue) {
AllocatableValue allocatable = (AllocatableValue) value;
Value result = proc.doValue(inst, allocatable, OperandMode.ALIVE, STATE_FLAGS);
if (!allocatable.identityEquals(result)) {
values[i] = (JavaValue) result;
}
} else if (value instanceof StackLockValue) {
StackLockValue monitor = (StackLockValue) value;
JavaValue owner = monitor.getOwner();
if (owner instanceof AllocatableValue) {
monitor.setOwner((JavaValue) proc.doValue(inst, (AllocatableValue) owner, OperandMode.ALIVE, STATE_FLAGS));
}
Value slot = monitor.getSlot();
if (isVirtualStackSlot(slot)) {
monitor.setSlot(asAllocatableValue(proc.doValue(inst, slot, OperandMode.ALIVE, STATE_FLAGS)));
}
} else {
assert unprocessed(value);
}
}
}
protected void visitValues(LIRInstruction inst, JavaValue[] values, InstructionValueConsumer proc) {
for (int i = 0; i < values.length; i++) {
JavaValue value = values[i];
if (isIllegalJavaValue(value)) {
continue;
} else if (value instanceof AllocatableValue) {
proc.visitValue(inst, (AllocatableValue) value, OperandMode.ALIVE, STATE_FLAGS);
} else if (value instanceof StackLockValue) {
StackLockValue monitor = (StackLockValue) value;
JavaValue owner = monitor.getOwner();
if (owner instanceof AllocatableValue) {
proc.visitValue(inst, (AllocatableValue) owner, OperandMode.ALIVE, STATE_FLAGS);
}
Value slot = monitor.getSlot();
if (isVirtualStackSlot(slot)) {
proc.visitValue(inst, slot, OperandMode.ALIVE, STATE_FLAGS);
}
} else {
assert unprocessed(value);
}
}
}
private boolean unprocessed(JavaValue value) {
if (isIllegalJavaValue(value)) {
return true;
} else if (isConstantJavaValue(value)) {
return true;
} else if (isVirtualObject(value)) {
assert Arrays.asList(virtualObjects).contains(value);
return true;
} else {
return false;
}
}
public void initDebugInfo(FrameMap frameMap, boolean canHaveRegisters) {
debugInfo = new DebugInfo(topFrame, virtualObjects);
}
public IndexedValueMap getLiveBasePointers() {
return liveBasePointers;
}
public void setLiveBasePointers(IndexedValueMap liveBasePointers) {
this.liveBasePointers = liveBasePointers;
}
@Override
public String toString() {
return debugInfo != null ? debugInfo.toString() : topFrame != null ? topFrame.toString() : "<empty>";
}
}