1 /*
   2  * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 package org.graalvm.compiler.nodes.debug.instrumentation;
  24 
  25 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
  26 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
  27 
  28 import org.graalvm.compiler.core.common.type.StampFactory;
  29 import org.graalvm.compiler.graph.NodeClass;
  30 import org.graalvm.compiler.graph.NodeInputList;
  31 import org.graalvm.compiler.nodeinfo.InputType;
  32 import org.graalvm.compiler.nodeinfo.NodeInfo;
  33 import org.graalvm.compiler.nodes.DeoptimizingFixedWithNextNode;
  34 import org.graalvm.compiler.nodes.FrameState;
  35 import org.graalvm.compiler.nodes.StructuredGraph;
  36 import org.graalvm.compiler.nodes.ValueNode;
  37 import org.graalvm.compiler.nodes.java.AccessMonitorNode;
  38 import org.graalvm.compiler.nodes.spi.VirtualizableAllocation;
  39 import org.graalvm.compiler.nodes.spi.VirtualizerTool;
  40 import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
  41 
  42 /**
  43  * The {@code InstrumentationNode} is a place holder of the instrumentation in the original graph.
  44  * It is generated at the ExtractInstrumentationPhase and substituted at the
  45  * InlineInstrumentationPhase. It maintains an instrumentation graph which contains the
  46  * instrumentation nodes in the original graph (between InstrumentationBeginNode and
  47  * InstrumentationEndNode). Any data dependency of the instrumentation nodes will be transformed
  48  * into an input to the InstrumentationNode.
  49  */
  50 @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
  51 public class InstrumentationNode extends DeoptimizingFixedWithNextNode implements VirtualizableAllocation {
  52 
  53     public static final NodeClass<InstrumentationNode> TYPE = NodeClass.create(InstrumentationNode.class);
  54 
  55     @OptionalInput(value = InputType.Unchecked) protected ValueNode target;
  56     @OptionalInput protected NodeInputList<ValueNode> weakDependencies;
  57 
  58     protected StructuredGraph instrumentationGraph;
  59     protected final boolean anchored;
  60 
  61     public InstrumentationNode(ValueNode target, boolean anchored) {
  62         this(target, anchored, 0, null);
  63     }
  64 
  65     private InstrumentationNode(ValueNode target, boolean anchored, int initialDependencySize, FrameState stateBefore) {
  66         super(TYPE, StampFactory.forVoid(), stateBefore);
  67 
  68         this.target = target;
  69         this.anchored = anchored;
  70         this.weakDependencies = new NodeInputList<>(this, initialDependencySize);
  71     }
  72 
  73     public ValueNode getTarget() {
  74         return target;
  75     }
  76 
  77     public boolean isAnchored() {
  78         return anchored;
  79     }
  80 
  81     public StructuredGraph getInstrumentationGraph() {
  82         return instrumentationGraph;
  83     }
  84 
  85     public void setInstrumentationGraph(StructuredGraph graph) {
  86         this.instrumentationGraph = graph;
  87     }
  88 
  89     public void addWeakDependency(ValueNode input) {
  90         weakDependencies.add(input);
  91     }
  92 
  93     public ValueNode getWeakDependency(int index) {
  94         return weakDependencies.get(index);
  95     }
  96 
  97     public NodeInputList<ValueNode> getWeakDependencies() {
  98         return weakDependencies;
  99     }
 100 
 101     /**
 102      * Clone the InstrumentationNode with the given new target. The weakDependencies will be
 103      * initialized with aliased nodes.
 104      */
 105     private InstrumentationNode cloneWithNewTarget(ValueNode newTarget, VirtualizerTool tool) {
 106         InstrumentationNode clone = new InstrumentationNode(newTarget, anchored, weakDependencies.size(), stateBefore);
 107         clone.instrumentationGraph = instrumentationGraph;
 108         for (int i = 0; i < weakDependencies.size(); i++) {
 109             ValueNode input = weakDependencies.get(i);
 110             if (!(input instanceof VirtualObjectNode)) {
 111                 ValueNode alias = tool.getAlias(input);
 112                 if (alias instanceof VirtualObjectNode) {
 113                     clone.weakDependencies.initialize(i, alias);
 114                     continue;
 115                 }
 116             }
 117             clone.weakDependencies.initialize(i, input);
 118         }
 119         return clone;
 120     }
 121 
 122     private boolean hasAliasedWeakDependency(VirtualizerTool tool) {
 123         for (ValueNode input : weakDependencies) {
 124             if (!(input instanceof VirtualObjectNode)) {
 125                 ValueNode alias = tool.getAlias(input);
 126                 if (alias instanceof VirtualObjectNode) {
 127                     return true;
 128                 }
 129             }
 130         }
 131         return false;
 132     }
 133 
 134     @Override
 135     public void virtualize(VirtualizerTool tool) {
 136         // InstrumentationNode allows non-materialized inputs. During the inlining of the
 137         // InstrumentationNode, non-materialized inputs will be replaced by null. The current
 138         // InstrumentationNode is replaced with a clone InstrumentationNode, such that the escape
 139         // analysis won't materialize non-materialized inputs at this point.
 140         InstrumentationNode replacee = null;
 141         if (target != null) {
 142             if (target instanceof AccessMonitorNode) {
 143                 AccessMonitorNode monitor = (AccessMonitorNode) target;
 144                 ValueNode alias = tool.getAlias(monitor.object());
 145                 if (alias instanceof VirtualObjectNode) {
 146                     MonitorProxyNode proxy = new MonitorProxyNode(null, monitor.getMonitorId());
 147                     tool.addNode(proxy);
 148                     replacee = cloneWithNewTarget(proxy, tool);
 149                 }
 150             } else if (!(target instanceof VirtualObjectNode)) {
 151                 ValueNode alias = tool.getAlias(target);
 152                 if (alias instanceof VirtualObjectNode) {
 153                     replacee = cloneWithNewTarget(alias, tool);
 154                 }
 155             }
 156         }
 157         if (replacee == null && hasAliasedWeakDependency(tool)) {
 158             replacee = cloneWithNewTarget(target, tool);
 159         }
 160         // in case of modification, we replace with the clone
 161         if (replacee != null) {
 162             tool.addNode(replacee);
 163             tool.replaceWithValue(replacee);
 164         }
 165     }
 166 
 167     @Override
 168     public boolean canDeoptimize() {
 169         return true;
 170     }
 171 
 172 }