1 /* 2 * Copyright (c) 2009, 2014, 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 24 25 package org.graalvm.compiler.nodes.virtual; 26 27 import static org.graalvm.compiler.nodeinfo.InputType.Association; 28 import static org.graalvm.compiler.nodeinfo.InputType.Extension; 29 import static org.graalvm.compiler.nodeinfo.InputType.Memory; 30 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN; 31 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN; 32 33 import java.util.ArrayList; 34 import java.util.Arrays; 35 import java.util.List; 36 import java.util.Map; 37 38 import org.graalvm.compiler.core.common.type.StampFactory; 39 import org.graalvm.compiler.graph.Node; 40 import org.graalvm.compiler.graph.NodeClass; 41 import org.graalvm.compiler.graph.NodeInputList; 42 import org.graalvm.compiler.graph.spi.Simplifiable; 43 import org.graalvm.compiler.graph.spi.SimplifierTool; 44 import org.graalvm.compiler.nodeinfo.NodeCycles; 45 import org.graalvm.compiler.nodeinfo.NodeInfo; 46 import org.graalvm.compiler.nodeinfo.NodeSize; 47 import org.graalvm.compiler.nodeinfo.Verbosity; 48 import org.graalvm.compiler.nodes.FixedWithNextNode; 49 import org.graalvm.compiler.nodes.NodeView; 50 import org.graalvm.compiler.nodes.ValueNode; 51 import org.graalvm.compiler.nodes.java.AbstractNewObjectNode; 52 import org.graalvm.compiler.nodes.java.MonitorIdNode; 53 import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; 54 import org.graalvm.compiler.nodes.memory.WriteNode; 55 import org.graalvm.compiler.nodes.spi.Lowerable; 56 import org.graalvm.compiler.nodes.spi.LoweringTool; 57 import org.graalvm.compiler.nodes.spi.VirtualizableAllocation; 58 import org.graalvm.compiler.nodes.spi.VirtualizerTool; 59 import jdk.internal.vm.compiler.word.LocationIdentity; 60 61 // @formatter:off 62 @NodeInfo(nameTemplate = "Alloc {i#virtualObjects}", 63 allowedUsageTypes = {Extension, Memory}, 64 cycles = CYCLES_UNKNOWN, 65 cyclesRationale = "We don't know statically how many, and which, allocations are done.", 66 size = SIZE_UNKNOWN, 67 sizeRationale = "We don't know statically how much code for which allocations has to be generated." 68 ) 69 // @formatter:on 70 public final class CommitAllocationNode extends FixedWithNextNode implements VirtualizableAllocation, Lowerable, Simplifiable, MemoryCheckpoint.Single { 71 72 public static final NodeClass<CommitAllocationNode> TYPE = NodeClass.create(CommitAllocationNode.class); 73 74 @Input NodeInputList<VirtualObjectNode> virtualObjects = new NodeInputList<>(this); 75 @Input NodeInputList<ValueNode> values = new NodeInputList<>(this); 76 @Input(Association) NodeInputList<MonitorIdNode> locks = new NodeInputList<>(this); 77 protected ArrayList<Integer> lockIndexes = new ArrayList<>(Arrays.asList(0)); 78 protected ArrayList<Boolean> ensureVirtual = new ArrayList<>(); 79 80 public CommitAllocationNode() { 81 super(TYPE, StampFactory.forVoid()); 82 } 83 84 public List<VirtualObjectNode> getVirtualObjects() { 85 return virtualObjects; 86 } 87 88 public List<ValueNode> getValues() { 89 return values; 90 } 91 92 public List<MonitorIdNode> getLocks(int objIndex) { 93 return locks.subList(lockIndexes.get(objIndex), lockIndexes.get(objIndex + 1)); 94 } 95 96 public List<Boolean> getEnsureVirtual() { 97 return ensureVirtual; 98 } 99 100 @Override 101 public boolean verify() { 102 assertTrue(virtualObjects.size() + 1 == lockIndexes.size(), "lockIndexes size doesn't match %s, %s", virtualObjects, lockIndexes); 103 assertTrue(lockIndexes.get(lockIndexes.size() - 1) == locks.size(), "locks size doesn't match %s,%s", lockIndexes, locks); 104 int valueCount = 0; 105 for (VirtualObjectNode virtual : virtualObjects) { 106 valueCount += virtual.entryCount(); 107 } 108 assertTrue(values.size() == valueCount, "values size doesn't match"); 109 assertTrue(virtualObjects.size() == ensureVirtual.size(), "ensureVirtual size doesn't match"); 110 return super.verify(); 111 } 112 113 @Override 114 public void lower(LoweringTool tool) { 115 for (int i = 0; i < virtualObjects.size(); i++) { 116 if (ensureVirtual.get(i)) { 117 EnsureVirtualizedNode.ensureVirtualFailure(this, virtualObjects.get(i).stamp(NodeView.DEFAULT)); 118 } 119 } 120 tool.getLowerer().lower(this, tool); 121 } 122 123 @Override 124 public LocationIdentity getLocationIdentity() { 125 return locks.isEmpty() ? LocationIdentity.init() : LocationIdentity.any(); 126 } 127 128 @Override 129 public void afterClone(Node other) { 130 lockIndexes = new ArrayList<>(lockIndexes); 131 } 132 133 public void addLocks(List<MonitorIdNode> monitorIds) { 134 locks.addAll(monitorIds); 135 lockIndexes.add(locks.size()); 136 } 137 138 @Override 139 public void virtualize(VirtualizerTool tool) { 140 int pos = 0; 141 for (int i = 0; i < virtualObjects.size(); i++) { 142 VirtualObjectNode virtualObject = virtualObjects.get(i); 143 int entryCount = virtualObject.entryCount(); 144 tool.createVirtualObject(virtualObject, values.subList(pos, pos + entryCount).toArray(new ValueNode[entryCount]), getLocks(i), ensureVirtual.get(i)); 145 pos += entryCount; 146 } 147 tool.delete(); 148 } 149 150 @Override 151 public Map<Object, Object> getDebugProperties(Map<Object, Object> map) { 152 Map<Object, Object> properties = super.getDebugProperties(map); 153 int valuePos = 0; 154 for (int objIndex = 0; objIndex < virtualObjects.size(); objIndex++) { 155 VirtualObjectNode virtual = virtualObjects.get(objIndex); 156 if (virtual == null) { 157 // Could occur in invalid graphs 158 properties.put("object(" + objIndex + ")", "null"); 159 continue; 160 } 161 StringBuilder s = new StringBuilder(); 162 s.append(virtual.type().toJavaName(false)).append("["); 163 for (int i = 0; i < virtual.entryCount(); i++) { 164 ValueNode value = values.get(valuePos++); 165 s.append(i == 0 ? "" : ",").append(value == null ? "_" : value.toString(Verbosity.Id)); 166 } 167 s.append("]"); 168 if (!getLocks(objIndex).isEmpty()) { 169 s.append(" locked(").append(getLocks(objIndex)).append(")"); 170 } 171 properties.put("object(" + virtual.toString(Verbosity.Id) + ")", s.toString()); 172 } 173 return properties; 174 } 175 176 @Override 177 public void simplify(SimplifierTool tool) { 178 boolean[] used = new boolean[virtualObjects.size()]; 179 int usedCount = 0; 180 for (AllocatedObjectNode addObject : usages().filter(AllocatedObjectNode.class)) { 181 int index = virtualObjects.indexOf(addObject.getVirtualObject()); 182 assert !used[index]; 183 used[index] = true; 184 usedCount++; 185 } 186 if (usedCount == 0) { 187 List<Node> inputSnapshot = inputs().snapshot(); 188 graph().removeFixed(this); 189 for (Node input : inputSnapshot) { 190 tool.removeIfUnused(input); 191 } 192 return; 193 } 194 boolean progress; 195 do { 196 progress = false; 197 int valuePos = 0; 198 for (int objIndex = 0; objIndex < virtualObjects.size(); objIndex++) { 199 VirtualObjectNode virtualObject = virtualObjects.get(objIndex); 200 if (used[objIndex]) { 201 for (int i = 0; i < virtualObject.entryCount(); i++) { 202 int index = virtualObjects.indexOf(values.get(valuePos + i)); 203 if (index != -1 && !used[index]) { 204 progress = true; 205 used[index] = true; 206 usedCount++; 207 } 208 } 209 } 210 valuePos += virtualObject.entryCount(); 211 } 212 213 } while (progress); 214 215 if (usedCount < virtualObjects.size()) { 216 List<VirtualObjectNode> newVirtualObjects = new ArrayList<>(usedCount); 217 List<MonitorIdNode> newLocks = new ArrayList<>(usedCount); 218 ArrayList<Integer> newLockIndexes = new ArrayList<>(usedCount + 1); 219 ArrayList<Boolean> newEnsureVirtual = new ArrayList<>(usedCount); 220 newLockIndexes.add(0); 221 List<ValueNode> newValues = new ArrayList<>(); 222 int valuePos = 0; 223 for (int objIndex = 0; objIndex < virtualObjects.size(); objIndex++) { 224 VirtualObjectNode virtualObject = virtualObjects.get(objIndex); 225 if (used[objIndex]) { 226 newVirtualObjects.add(virtualObject); 227 newLocks.addAll(getLocks(objIndex)); 228 newLockIndexes.add(newLocks.size()); 229 newValues.addAll(values.subList(valuePos, valuePos + virtualObject.entryCount())); 230 newEnsureVirtual.add(ensureVirtual.get(objIndex)); 231 } 232 valuePos += virtualObject.entryCount(); 233 } 234 virtualObjects.clear(); 235 virtualObjects.addAll(newVirtualObjects); 236 locks.clear(); 237 locks.addAll(newLocks); 238 values.clear(); 239 values.addAll(newValues); 240 lockIndexes = newLockIndexes; 241 ensureVirtual = newEnsureVirtual; 242 } 243 } 244 245 @Override 246 public NodeCycles estimatedNodeCycles() { 247 List<VirtualObjectNode> v = getVirtualObjects(); 248 int fieldWriteCount = 0; 249 for (int i = 0; i < v.size(); i++) { 250 fieldWriteCount += v.get(i).entryCount(); 251 } 252 int rawValueWrites = NodeCycles.compute(WriteNode.TYPE.cycles(), fieldWriteCount).value; 253 int rawValuesTlabBumps = AbstractNewObjectNode.TYPE.cycles().value; 254 return NodeCycles.compute(rawValueWrites + rawValuesTlabBumps); 255 } 256 257 @Override 258 public NodeSize estimatedNodeSize() { 259 List<VirtualObjectNode> v = getVirtualObjects(); 260 int fieldWriteCount = 0; 261 for (int i = 0; i < v.size(); i++) { 262 fieldWriteCount += v.get(i).entryCount(); 263 } 264 int rawValueWrites = NodeSize.compute(WriteNode.TYPE.size(), fieldWriteCount).value; 265 int rawValuesTlabBumps = AbstractNewObjectNode.TYPE.size().value; 266 return NodeSize.compute(rawValueWrites + rawValuesTlabBumps); 267 } 268 }