001/*
002 * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023package com.oracle.graal.nodes.virtual;
024
025import java.util.*;
026
027import com.oracle.graal.compiler.common.type.*;
028import com.oracle.graal.graph.*;
029import com.oracle.graal.graph.spi.*;
030import com.oracle.graal.nodeinfo.*;
031import com.oracle.graal.nodes.*;
032import com.oracle.graal.nodes.java.*;
033import com.oracle.graal.nodes.spi.*;
034
035@NodeInfo(nameTemplate = "Alloc {i#virtualObjects}", allowedUsageTypes = {InputType.Extension})
036public final class CommitAllocationNode extends FixedWithNextNode implements VirtualizableAllocation, Lowerable, Simplifiable {
037
038    public static final NodeClass<CommitAllocationNode> TYPE = NodeClass.create(CommitAllocationNode.class);
039
040    @Input NodeInputList<VirtualObjectNode> virtualObjects = new NodeInputList<>(this);
041    @Input NodeInputList<ValueNode> values = new NodeInputList<>(this);
042    @Input(InputType.Association) NodeInputList<MonitorIdNode> locks = new NodeInputList<>(this);
043    protected ArrayList<Integer> lockIndexes = new ArrayList<>(Arrays.asList(0));
044    protected ArrayList<Boolean> ensureVirtual = new ArrayList<>();
045
046    public CommitAllocationNode() {
047        super(TYPE, StampFactory.forVoid());
048    }
049
050    public List<VirtualObjectNode> getVirtualObjects() {
051        return virtualObjects;
052    }
053
054    public List<ValueNode> getValues() {
055        return values;
056    }
057
058    public List<MonitorIdNode> getLocks(int objIndex) {
059        return locks.subList(lockIndexes.get(objIndex), lockIndexes.get(objIndex + 1));
060    }
061
062    public List<Boolean> getEnsureVirtual() {
063        return ensureVirtual;
064    }
065
066    @Override
067    public boolean verify() {
068        assertTrue(virtualObjects.size() + 1 == lockIndexes.size(), "lockIndexes size doesn't match " + virtualObjects + ", " + lockIndexes);
069        assertTrue(lockIndexes.get(lockIndexes.size() - 1) == locks.size(), "locks size doesn't match " + lockIndexes + ", " + locks);
070        int valueCount = 0;
071        for (VirtualObjectNode virtual : virtualObjects) {
072            valueCount += virtual.entryCount();
073        }
074        assertTrue(values.size() == valueCount, "values size doesn't match");
075        assertTrue(virtualObjects.size() == ensureVirtual.size(), "ensureVirtual size doesn't match");
076        return super.verify();
077    }
078
079    @Override
080    public void lower(LoweringTool tool) {
081        for (int i = 0; i < virtualObjects.size(); i++) {
082            if (ensureVirtual.get(i)) {
083                EnsureVirtualizedNode.ensureVirtualFailure(this, virtualObjects.get(i).stamp());
084            }
085        }
086        tool.getLowerer().lower(this, tool);
087    }
088
089    @Override
090    public void afterClone(Node other) {
091        lockIndexes = new ArrayList<>(lockIndexes);
092    }
093
094    public void addLocks(List<MonitorIdNode> monitorIds) {
095        locks.addAll(monitorIds);
096        lockIndexes.add(locks.size());
097    }
098
099    @Override
100    public void virtualize(VirtualizerTool tool) {
101        int pos = 0;
102        for (int i = 0; i < virtualObjects.size(); i++) {
103            VirtualObjectNode virtualObject = virtualObjects.get(i);
104            int entryCount = virtualObject.entryCount();
105            tool.createVirtualObject(virtualObject, values.subList(pos, pos + entryCount).toArray(new ValueNode[entryCount]), getLocks(i), ensureVirtual.get(i));
106            pos += entryCount;
107        }
108        tool.delete();
109    }
110
111    @Override
112    public Map<Object, Object> getDebugProperties(Map<Object, Object> map) {
113        Map<Object, Object> properties = super.getDebugProperties(map);
114        int valuePos = 0;
115        for (int objIndex = 0; objIndex < virtualObjects.size(); objIndex++) {
116            VirtualObjectNode virtual = virtualObjects.get(objIndex);
117            if (virtual == null) {
118                // Could occur in invalid graphs
119                properties.put("object(" + objIndex + ")", "null");
120                continue;
121            }
122            StringBuilder s = new StringBuilder();
123            s.append(virtual.type().toJavaName(false)).append("[");
124            for (int i = 0; i < virtual.entryCount(); i++) {
125                ValueNode value = values.get(valuePos++);
126                s.append(i == 0 ? "" : ",").append(value == null ? "_" : value.toString(Verbosity.Id));
127            }
128            s.append("]");
129            if (!getLocks(objIndex).isEmpty()) {
130                s.append(" locked(").append(getLocks(objIndex)).append(")");
131            }
132            properties.put("object(" + virtual.toString(Verbosity.Id) + ")", s.toString());
133        }
134        return properties;
135    }
136
137    @Override
138    public void simplify(SimplifierTool tool) {
139        boolean[] used = new boolean[virtualObjects.size()];
140        int usedCount = 0;
141        for (Node usage : usages()) {
142            AllocatedObjectNode addObject = (AllocatedObjectNode) usage;
143            int index = virtualObjects.indexOf(addObject.getVirtualObject());
144            assert !used[index];
145            used[index] = true;
146            usedCount++;
147        }
148        if (usedCount == 0) {
149            List<Node> inputSnapshot = inputs().snapshot();
150            graph().removeFixed(this);
151            for (Node input : inputSnapshot) {
152                tool.removeIfUnused(input);
153            }
154            return;
155        }
156        boolean progress;
157        do {
158            progress = false;
159            int valuePos = 0;
160            for (int objIndex = 0; objIndex < virtualObjects.size(); objIndex++) {
161                VirtualObjectNode virtualObject = virtualObjects.get(objIndex);
162                if (used[objIndex]) {
163                    for (int i = 0; i < virtualObject.entryCount(); i++) {
164                        int index = virtualObjects.indexOf(values.get(valuePos + i));
165                        if (index != -1 && !used[index]) {
166                            progress = true;
167                            used[index] = true;
168                            usedCount++;
169                        }
170                    }
171                }
172                valuePos += virtualObject.entryCount();
173            }
174
175        } while (progress);
176
177        if (usedCount < virtualObjects.size()) {
178            List<VirtualObjectNode> newVirtualObjects = new ArrayList<>(usedCount);
179            List<MonitorIdNode> newLocks = new ArrayList<>(usedCount);
180            ArrayList<Integer> newLockIndexes = new ArrayList<>(usedCount + 1);
181            ArrayList<Boolean> newEnsureVirtual = new ArrayList<>(usedCount);
182            newLockIndexes.add(0);
183            List<ValueNode> newValues = new ArrayList<>();
184            int valuePos = 0;
185            for (int objIndex = 0; objIndex < virtualObjects.size(); objIndex++) {
186                VirtualObjectNode virtualObject = virtualObjects.get(objIndex);
187                if (used[objIndex]) {
188                    newVirtualObjects.add(virtualObject);
189                    newLocks.addAll(getLocks(objIndex));
190                    newLockIndexes.add(newLocks.size());
191                    newValues.addAll(values.subList(valuePos, valuePos + virtualObject.entryCount()));
192                    newEnsureVirtual.add(ensureVirtual.get(objIndex));
193                }
194                valuePos += virtualObject.entryCount();
195            }
196            virtualObjects.clear();
197            virtualObjects.addAll(newVirtualObjects);
198            locks.clear();
199            locks.addAll(newLocks);
200            values.clear();
201            values.addAll(newValues);
202            lockIndexes = newLockIndexes;
203            ensureVirtual = newEnsureVirtual;
204        }
205    }
206
207}