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