package org.graalvm.compiler.nodes.debug.instrumentation;
import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
import org.graalvm.compiler.core.common.type.StampFactory;
import org.graalvm.compiler.graph.NodeClass;
import org.graalvm.compiler.graph.NodeInputList;
import org.graalvm.compiler.nodeinfo.InputType;
import org.graalvm.compiler.nodeinfo.NodeInfo;
import org.graalvm.compiler.nodes.DeoptimizingFixedWithNextNode;
import org.graalvm.compiler.nodes.FrameState;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.ValueNode;
import org.graalvm.compiler.nodes.java.AccessMonitorNode;
import org.graalvm.compiler.nodes.spi.VirtualizableAllocation;
import org.graalvm.compiler.nodes.spi.VirtualizerTool;
import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
@NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
public class InstrumentationNode extends DeoptimizingFixedWithNextNode implements VirtualizableAllocation {
public static final NodeClass<InstrumentationNode> TYPE = NodeClass.create(InstrumentationNode.class);
@OptionalInput(value = InputType.Unchecked) protected ValueNode target;
@OptionalInput protected NodeInputList<ValueNode> weakDependencies;
protected StructuredGraph instrumentationGraph;
protected final boolean anchored;
public InstrumentationNode(ValueNode target, boolean anchored) {
this(target, anchored, 0, null);
}
private InstrumentationNode(ValueNode target, boolean anchored, int initialDependencySize, FrameState stateBefore) {
super(TYPE, StampFactory.forVoid(), stateBefore);
this.target = target;
this.anchored = anchored;
this.weakDependencies = new NodeInputList<>(this, initialDependencySize);
}
public ValueNode getTarget() {
return target;
}
public boolean isAnchored() {
return anchored;
}
public StructuredGraph getInstrumentationGraph() {
return instrumentationGraph;
}
public void setInstrumentationGraph(StructuredGraph graph) {
this.instrumentationGraph = graph;
}
public void addWeakDependency(ValueNode input) {
weakDependencies.add(input);
}
public ValueNode getWeakDependency(int index) {
return weakDependencies.get(index);
}
public NodeInputList<ValueNode> getWeakDependencies() {
return weakDependencies;
}
private InstrumentationNode cloneWithNewTarget(ValueNode newTarget, VirtualizerTool tool) {
InstrumentationNode clone = new InstrumentationNode(newTarget, anchored, weakDependencies.size(), stateBefore);
clone.instrumentationGraph = instrumentationGraph;
for (int i = 0; i < weakDependencies.size(); i++) {
ValueNode input = weakDependencies.get(i);
if (!(input instanceof VirtualObjectNode)) {
ValueNode alias = tool.getAlias(input);
if (alias instanceof VirtualObjectNode) {
clone.weakDependencies.initialize(i, alias);
continue;
}
}
clone.weakDependencies.initialize(i, input);
}
return clone;
}
private boolean hasAliasedWeakDependency(VirtualizerTool tool) {
for (ValueNode input : weakDependencies) {
if (!(input instanceof VirtualObjectNode)) {
ValueNode alias = tool.getAlias(input);
if (alias instanceof VirtualObjectNode) {
return true;
}
}
}
return false;
}
@Override
public void virtualize(VirtualizerTool tool) {
InstrumentationNode replacee = null;
if (target != null) {
if (target instanceof AccessMonitorNode) {
AccessMonitorNode monitor = (AccessMonitorNode) target;
ValueNode alias = tool.getAlias(monitor.object());
if (alias instanceof VirtualObjectNode) {
MonitorProxyNode proxy = new MonitorProxyNode(null, monitor.getMonitorId());
tool.addNode(proxy);
replacee = cloneWithNewTarget(proxy, tool);
}
} else if (!(target instanceof VirtualObjectNode)) {
ValueNode alias = tool.getAlias(target);
if (alias instanceof VirtualObjectNode) {
replacee = cloneWithNewTarget(alias, tool);
}
}
}
if (replacee == null && hasAliasedWeakDependency(tool)) {
replacee = cloneWithNewTarget(target, tool);
}
if (replacee != null) {
tool.addNode(replacee);
tool.replaceWithValue(replacee);
}
}
@Override
public boolean canDeoptimize() {
return true;
}
}