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 }