/*
 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
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;

The InstrumentationNode is a place holder of the instrumentation in the original graph. It is generated at the ExtractInstrumentationPhase and substituted at the InlineInstrumentationPhase. It maintains an instrumentation graph which contains the instrumentation nodes in the original graph (between InstrumentationBeginNode and InstrumentationEndNode). Any data dependency of the instrumentation nodes will be transformed into an input to the InstrumentationNode.
/** * The {@code InstrumentationNode} is a place holder of the instrumentation in the original graph. * It is generated at the ExtractInstrumentationPhase and substituted at the * InlineInstrumentationPhase. It maintains an instrumentation graph which contains the * instrumentation nodes in the original graph (between InstrumentationBeginNode and * InstrumentationEndNode). Any data dependency of the instrumentation nodes will be transformed * into an input to the InstrumentationNode. */
@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; }
Clone the InstrumentationNode with the given new target. The weakDependencies will be initialized with aliased nodes.
/** * Clone the InstrumentationNode with the given new target. The weakDependencies will be * initialized with aliased nodes. */
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 allows non-materialized inputs. During the inlining of the // InstrumentationNode, non-materialized inputs will be replaced by null. The current // InstrumentationNode is replaced with a clone InstrumentationNode, such that the escape // analysis won't materialize non-materialized inputs at this point. 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); } // in case of modification, we replace with the clone if (replacee != null) { tool.addNode(replacee); tool.replaceWithValue(replacee); } } @Override public boolean canDeoptimize() { return true; } }