--- /dev/null 2017-01-22 10:16:57.869617664 -0800 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/CommitAllocationNode.java 2017-02-15 17:07:59.401168124 -0800 @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2009, 2014, 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.virtual; + +import static org.graalvm.compiler.nodeinfo.InputType.Association; +import static org.graalvm.compiler.nodeinfo.InputType.Extension; +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.graph.NodeInputList; +import org.graalvm.compiler.graph.spi.Simplifiable; +import org.graalvm.compiler.graph.spi.SimplifierTool; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodeinfo.Verbosity; +import org.graalvm.compiler.nodes.FixedWithNextNode; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.java.MonitorIdNode; +import org.graalvm.compiler.nodes.spi.Lowerable; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.nodes.spi.VirtualizableAllocation; +import org.graalvm.compiler.nodes.spi.VirtualizerTool; + +// @formatter:off +@NodeInfo(nameTemplate = "Alloc {i#virtualObjects}", + allowedUsageTypes = Extension, + cycles = CYCLES_UNKNOWN, + cyclesRationale = "We don't know statically how many, and which, allocations are done.", + size = SIZE_UNKNOWN, + sizeRationale = "We don't know statically how much code for which allocations has to be generated." +) +// @formatter:on +public final class CommitAllocationNode extends FixedWithNextNode implements VirtualizableAllocation, Lowerable, Simplifiable { + + public static final NodeClass TYPE = NodeClass.create(CommitAllocationNode.class); + + @Input NodeInputList virtualObjects = new NodeInputList<>(this); + @Input NodeInputList values = new NodeInputList<>(this); + @Input(Association) NodeInputList locks = new NodeInputList<>(this); + protected ArrayList lockIndexes = new ArrayList<>(Arrays.asList(0)); + protected ArrayList ensureVirtual = new ArrayList<>(); + + public CommitAllocationNode() { + super(TYPE, StampFactory.forVoid()); + } + + public List getVirtualObjects() { + return virtualObjects; + } + + public List getValues() { + return values; + } + + public List getLocks(int objIndex) { + return locks.subList(lockIndexes.get(objIndex), lockIndexes.get(objIndex + 1)); + } + + public List getEnsureVirtual() { + return ensureVirtual; + } + + @Override + public boolean verify() { + assertTrue(virtualObjects.size() + 1 == lockIndexes.size(), "lockIndexes size doesn't match %s, %s", virtualObjects, lockIndexes); + assertTrue(lockIndexes.get(lockIndexes.size() - 1) == locks.size(), "locks size doesn't match %s,%s", lockIndexes, locks); + int valueCount = 0; + for (VirtualObjectNode virtual : virtualObjects) { + valueCount += virtual.entryCount(); + } + assertTrue(values.size() == valueCount, "values size doesn't match"); + assertTrue(virtualObjects.size() == ensureVirtual.size(), "ensureVirtual size doesn't match"); + return super.verify(); + } + + @Override + public void lower(LoweringTool tool) { + for (int i = 0; i < virtualObjects.size(); i++) { + if (ensureVirtual.get(i)) { + EnsureVirtualizedNode.ensureVirtualFailure(this, virtualObjects.get(i).stamp()); + } + } + tool.getLowerer().lower(this, tool); + } + + @Override + public void afterClone(Node other) { + lockIndexes = new ArrayList<>(lockIndexes); + } + + public void addLocks(List monitorIds) { + locks.addAll(monitorIds); + lockIndexes.add(locks.size()); + } + + @Override + public void virtualize(VirtualizerTool tool) { + int pos = 0; + for (int i = 0; i < virtualObjects.size(); i++) { + VirtualObjectNode virtualObject = virtualObjects.get(i); + int entryCount = virtualObject.entryCount(); + tool.createVirtualObject(virtualObject, values.subList(pos, pos + entryCount).toArray(new ValueNode[entryCount]), getLocks(i), ensureVirtual.get(i)); + pos += entryCount; + } + tool.delete(); + } + + @Override + public Map getDebugProperties(Map map) { + Map properties = super.getDebugProperties(map); + int valuePos = 0; + for (int objIndex = 0; objIndex < virtualObjects.size(); objIndex++) { + VirtualObjectNode virtual = virtualObjects.get(objIndex); + if (virtual == null) { + // Could occur in invalid graphs + properties.put("object(" + objIndex + ")", "null"); + continue; + } + StringBuilder s = new StringBuilder(); + s.append(virtual.type().toJavaName(false)).append("["); + for (int i = 0; i < virtual.entryCount(); i++) { + ValueNode value = values.get(valuePos++); + s.append(i == 0 ? "" : ",").append(value == null ? "_" : value.toString(Verbosity.Id)); + } + s.append("]"); + if (!getLocks(objIndex).isEmpty()) { + s.append(" locked(").append(getLocks(objIndex)).append(")"); + } + properties.put("object(" + virtual.toString(Verbosity.Id) + ")", s.toString()); + } + return properties; + } + + @Override + public void simplify(SimplifierTool tool) { + boolean[] used = new boolean[virtualObjects.size()]; + int usedCount = 0; + for (Node usage : usages()) { + AllocatedObjectNode addObject = (AllocatedObjectNode) usage; + int index = virtualObjects.indexOf(addObject.getVirtualObject()); + assert !used[index]; + used[index] = true; + usedCount++; + } + if (usedCount == 0) { + List inputSnapshot = inputs().snapshot(); + graph().removeFixed(this); + for (Node input : inputSnapshot) { + tool.removeIfUnused(input); + } + return; + } + boolean progress; + do { + progress = false; + int valuePos = 0; + for (int objIndex = 0; objIndex < virtualObjects.size(); objIndex++) { + VirtualObjectNode virtualObject = virtualObjects.get(objIndex); + if (used[objIndex]) { + for (int i = 0; i < virtualObject.entryCount(); i++) { + int index = virtualObjects.indexOf(values.get(valuePos + i)); + if (index != -1 && !used[index]) { + progress = true; + used[index] = true; + usedCount++; + } + } + } + valuePos += virtualObject.entryCount(); + } + + } while (progress); + + if (usedCount < virtualObjects.size()) { + List newVirtualObjects = new ArrayList<>(usedCount); + List newLocks = new ArrayList<>(usedCount); + ArrayList newLockIndexes = new ArrayList<>(usedCount + 1); + ArrayList newEnsureVirtual = new ArrayList<>(usedCount); + newLockIndexes.add(0); + List newValues = new ArrayList<>(); + int valuePos = 0; + for (int objIndex = 0; objIndex < virtualObjects.size(); objIndex++) { + VirtualObjectNode virtualObject = virtualObjects.get(objIndex); + if (used[objIndex]) { + newVirtualObjects.add(virtualObject); + newLocks.addAll(getLocks(objIndex)); + newLockIndexes.add(newLocks.size()); + newValues.addAll(values.subList(valuePos, valuePos + virtualObject.entryCount())); + newEnsureVirtual.add(ensureVirtual.get(objIndex)); + } + valuePos += virtualObject.entryCount(); + } + virtualObjects.clear(); + virtualObjects.addAll(newVirtualObjects); + locks.clear(); + locks.addAll(newLocks); + values.clear(); + values.addAll(newValues); + lockIndexes = newLockIndexes; + ensureVirtual = newEnsureVirtual; + } + } + + /** + * For all the virtual object nodes that depends on commit allocation, this method maps the node + * with its values. For example, a commit allocation could depend on a {@link VirtualArrayNode} + * with many {@link ValueNode}s. The map will contain the corresponding {@link VirtualArrayNode} + * as a key with the array of {@link ValueNode}s. + */ + public HashMap getVirtualObjectsArrays() { + HashMap arrayValues = new HashMap<>(); + int pos = 0; + for (int i = 0; i < virtualObjects.size(); i++) { + VirtualObjectNode virtualObject = virtualObjects.get(i); + int entryCount = virtualObject.entryCount(); + ValueNode[] array = values.subList(pos, pos + entryCount).toArray(new ValueNode[entryCount]); + arrayValues.put(virtualObject, array); + pos += entryCount; + } + return arrayValues; + } + +}