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.phases.common.instrumentation; 24 25 import java.util.HashMap; 26 27 import org.graalvm.compiler.graph.Node; 28 import org.graalvm.compiler.graph.NodeFlood; 29 import org.graalvm.compiler.nodes.AbstractEndNode; 30 import org.graalvm.compiler.nodes.FixedNode; 31 import org.graalvm.compiler.nodes.FixedWithNextNode; 32 import org.graalvm.compiler.nodes.LoopEndNode; 33 import org.graalvm.compiler.nodes.StructuredGraph; 34 import org.graalvm.compiler.nodes.ValueNode; 35 import org.graalvm.compiler.nodes.debug.instrumentation.InstrumentationNode; 36 import org.graalvm.compiler.nodes.debug.instrumentation.MonitorProxyNode; 37 import org.graalvm.compiler.nodes.java.MonitorIdNode; 38 import org.graalvm.compiler.nodes.virtual.AllocatedObjectNode; 39 import org.graalvm.compiler.nodes.virtual.CommitAllocationNode; 40 import org.graalvm.compiler.nodes.virtual.VirtualObjectNode; 41 import org.graalvm.compiler.phases.Phase; 42 43 /** 44 * The {@code HighTierReconcileInstrumentationPhase} reconciles the InstrumentationNodes according 45 * to the optimizations at the high tier, e.g., the partial escape analysis. It clones the 46 * InstrumentationNode and inserts at the CommitAllocationNode that includes the allocation/lock 47 * targeted by the InstrumentationNode. 48 */ 49 public class HighTierReconcileInstrumentationPhase extends Phase { 50 51 @Override 52 public boolean checkContract() { 53 return false; 54 } 55 56 @Override 57 protected void run(StructuredGraph graph) { 58 // iterate through all CommitAllocationNodes, and clone the InstrumentationNodes targeting 59 // allocation/lock held by this CommitAllocationNode 60 for (CommitAllocationNode commit : graph.getNodes().filter(CommitAllocationNode.class)) { 61 InstrumentationAggregation aggr = new InstrumentationAggregation(graph, commit); 62 // iterate through all VirtualObjectNodes held by the CommitAllocationNode, clone if any 63 // InstrumentationNode targets one of these VirtualObjectNodes 64 for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) { 65 VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex); 66 for (InstrumentationNode instrumentationNode : graph.getNodes().filter(InstrumentationNode.class)) { 67 if (isCFGAccessible(instrumentationNode, commit) && instrumentationNode.getTarget() == virtual) { 68 // clone InstrumentationNode when the CommitAllocationNode is accessible 69 // from the InstrumentationNode, and the InstrumentationNode's target 70 // matches the given VirtualObjectNode 71 aggr.insertClone(instrumentationNode, getAllocatedObject(graph, commit, virtual)); 72 } 73 } 74 } 75 // iterate through all MonitorIdNodes held by the CommitAllocationNode, clone if any 76 // InstrumentationNode targets one of these MonitorIdNodes (via MonitorProxyNode) 77 for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) { 78 VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex); 79 for (MonitorIdNode monitorId : commit.getLocks(objIndex)) { 80 for (InstrumentationNode instrumentationNode : graph.getNodes().filter(InstrumentationNode.class)) { 81 if (isCFGAccessible(instrumentationNode, commit) && instrumentationNode.getTarget() instanceof MonitorProxyNode && 82 ((MonitorProxyNode) instrumentationNode.getTarget()).getMonitorId() == monitorId) { 83 // clone InstrumentationNode when the CommitAllocationNode is accessible 84 // from the InstrumentationNode, and the InstrumentationNode's target is 85 // a MonitorProxyNode that matches the MonitorIdNode 86 aggr.insertClone(instrumentationNode, graph.addWithoutUnique(new MonitorProxyNode(getAllocatedObject(graph, commit, virtual), monitorId))); 87 } 88 } 89 } 90 } 91 } 92 // remove InstrumentationNodes that still target virtual nodes 93 for (InstrumentationNode instrumentationNode : graph.getNodes().filter(InstrumentationNode.class)) { 94 ValueNode target = instrumentationNode.getTarget(); 95 if (target instanceof VirtualObjectNode) { 96 graph.removeFixed(instrumentationNode); 97 } else if (target instanceof MonitorProxyNode) { 98 MonitorProxyNode proxy = (MonitorProxyNode) target; 99 if (proxy.object() == null) { 100 graph.removeFixed(instrumentationNode); 101 } 102 } 103 } 104 } 105 106 /** 107 * The {@code InstrumentationAggregation} maintains an inserting location after 108 * CommitAllocationNode such that the cloned InstrumentationNodes would appear in the order of 109 * the allocations. 110 */ 111 class InstrumentationAggregation { 112 113 private StructuredGraph graph; 114 private CommitAllocationNode commit; 115 private FixedWithNextNode insertAfter; 116 117 InstrumentationAggregation(StructuredGraph graph, CommitAllocationNode commit) { 118 this.graph = graph; 119 this.commit = commit; 120 this.insertAfter = commit; 121 } 122 123 void insertClone(InstrumentationNode instrumentationNode, ValueNode newTarget) { 124 InstrumentationNode clone = (InstrumentationNode) instrumentationNode.copyWithInputs(); 125 // update the clone instrumentation node with the new target 126 clone.replaceFirstInput(clone.getTarget(), newTarget); 127 // update weak dependencies of the clone instrumentation node where the dependency 128 // is also a VirtualObjectNode. This is common when one allocation in the 129 // CommitAllocationNode depends on another allocation. 130 for (ValueNode input : clone.getWeakDependencies()) { 131 if ((input instanceof VirtualObjectNode) && (commit.getVirtualObjects().contains(input))) { 132 clone.replaceFirstInput(input, getAllocatedObject(graph, commit, (VirtualObjectNode) input)); 133 } 134 } 135 graph.addAfterFixed(insertAfter, clone); 136 insertAfter = clone; 137 } 138 139 } 140 141 private final HashMap<FixedWithNextNode, NodeFlood> cachedNodeFloods = new HashMap<>(); 142 143 /** 144 * @return true if there is a control flow path between {@code from} and {@code to}. 145 */ 146 private boolean isCFGAccessible(FixedWithNextNode from, FixedNode to) { 147 NodeFlood flood = cachedNodeFloods.get(from); 148 if (flood == null) { 149 flood = from.graph().createNodeFlood(); 150 flood.add(from); 151 for (Node current : flood) { 152 if (current instanceof LoopEndNode) { 153 continue; 154 } else if (current instanceof AbstractEndNode) { 155 flood.add(((AbstractEndNode) current).merge()); 156 } else { 157 flood.addAll(current.successors()); 158 } 159 } 160 cachedNodeFloods.put(from, flood); 161 } 162 return flood.isMarked(to); 163 } 164 165 /** 166 * Get/generate the AllocatedObjectNode for the given VirtualObjectNode in the given 167 * CommitAllocationNode. 168 */ 169 private static AllocatedObjectNode getAllocatedObject(StructuredGraph graph, CommitAllocationNode commit, VirtualObjectNode virtual) { 170 // search if the AllocatedObjectNode already exists 171 for (AllocatedObjectNode allocatedObject : graph.getNodes().filter(AllocatedObjectNode.class)) { 172 if (allocatedObject.getCommit() == commit && allocatedObject.getVirtualObject() == virtual) { 173 return allocatedObject; 174 } 175 } 176 // create one if the AllocatedObjectNode does not exist 177 AllocatedObjectNode allocatedObject = graph.addWithoutUnique(new AllocatedObjectNode(virtual)); 178 allocatedObject.setCommit(commit); 179 return allocatedObject; 180 } 181 182 }