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