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