1/*
2 * Copyright (c) 2015, 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.NodeCycles.CYCLES_0;
26import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
27
28import org.graalvm.compiler.core.common.type.Stamp;
29import org.graalvm.compiler.core.common.type.StampFactory;
30import org.graalvm.compiler.graph.Node;
31import org.graalvm.compiler.graph.NodeClass;
32import org.graalvm.compiler.graph.VerificationError;
33import org.graalvm.compiler.nodeinfo.NodeInfo;
34import org.graalvm.compiler.nodes.AbstractEndNode;
35import org.graalvm.compiler.nodes.FixedNode;
36import org.graalvm.compiler.nodes.FixedWithNextNode;
37import org.graalvm.compiler.nodes.Invoke;
38import org.graalvm.compiler.nodes.ValueNode;
39import org.graalvm.compiler.nodes.java.StoreFieldNode;
40import org.graalvm.compiler.nodes.spi.Lowerable;
41import org.graalvm.compiler.nodes.spi.LoweringTool;
42import org.graalvm.compiler.nodes.spi.Virtualizable;
43import org.graalvm.compiler.nodes.spi.VirtualizerTool;
44import org.graalvm.compiler.nodes.type.StampTool;
45import org.graalvm.compiler.nodes.util.GraphUtil;
46
47@NodeInfo(cycles = CYCLES_0, size = SIZE_0)
48public final class EnsureVirtualizedNode extends FixedWithNextNode implements Virtualizable, Lowerable {
49
50    public static final NodeClass<EnsureVirtualizedNode> TYPE = NodeClass.create(EnsureVirtualizedNode.class);
51
52    @Input ValueNode object;
53    private final boolean localOnly;
54
55    public EnsureVirtualizedNode(ValueNode object, boolean localOnly) {
56        super(TYPE, StampFactory.forVoid());
57        this.object = object;
58        this.localOnly = localOnly;
59    }
60
61    @Override
62    public void virtualize(VirtualizerTool tool) {
63        ValueNode alias = tool.getAlias(object);
64        if (alias instanceof VirtualObjectNode) {
65            VirtualObjectNode virtual = (VirtualObjectNode) alias;
66            if (virtual instanceof VirtualBoxingNode) {
67                Throwable exception = new VerificationError("ensureVirtual is not valid for boxing objects: %s", virtual.type().getName());
68                throw GraphUtil.approxSourceException(this, exception);
69            }
70            if (!localOnly) {
71                tool.setEnsureVirtualized(virtual, true);
72            }
73            tool.delete();
74        }
75    }
76
77    @Override
78    public void lower(LoweringTool tool) {
79        ensureVirtualFailure(this, object.stamp());
80    }
81
82    public static void ensureVirtualFailure(Node location, Stamp stamp) {
83        String additionalReason = "";
84        if (location instanceof FixedWithNextNode && !(location instanceof EnsureVirtualizedNode)) {
85            FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) location;
86            FixedNode next = fixedWithNextNode.next();
87            if (next instanceof StoreFieldNode) {
88                additionalReason = " (must not store virtual object into a field)";
89            } else if (next instanceof Invoke) {
90                additionalReason = " (must not pass virtual object into an invoke that cannot be inlined)";
91            } else {
92                additionalReason = " (must not let virtual object escape at node " + next + ")";
93            }
94        }
95        Throwable exception = new VerificationError("Object of type %s should not be materialized%s:", StampTool.typeOrNull(stamp).getName(), additionalReason);
96
97        Node pos;
98        if (location instanceof FixedWithNextNode) {
99            pos = ((FixedWithNextNode) location).next();
100        } else if (location instanceof AbstractEndNode) {
101            pos = ((AbstractEndNode) location).merge();
102        } else {
103            pos = location;
104        }
105        throw GraphUtil.approxSourceException(pos, exception);
106    }
107}
108