InvokeNode.java revision 12651:6ef01bd40ce2
1/*
2 * Copyright (c) 2009, 2016, 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;
24
25import static org.graalvm.compiler.nodeinfo.InputType.Extension;
26import static org.graalvm.compiler.nodeinfo.InputType.Guard;
27import static org.graalvm.compiler.nodeinfo.InputType.Memory;
28import static org.graalvm.compiler.nodeinfo.InputType.State;
29import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
30import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN;
31
32import java.util.Map;
33
34import org.graalvm.compiler.core.common.LocationIdentity;
35import org.graalvm.compiler.core.common.type.Stamp;
36import org.graalvm.compiler.graph.Node;
37import org.graalvm.compiler.graph.NodeClass;
38import org.graalvm.compiler.nodeinfo.InputType;
39import org.graalvm.compiler.nodeinfo.NodeInfo;
40import org.graalvm.compiler.nodeinfo.Verbosity;
41import org.graalvm.compiler.nodes.extended.ForeignCallNode;
42import org.graalvm.compiler.nodes.extended.GuardingNode;
43import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
44import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint;
45import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
46import org.graalvm.compiler.nodes.spi.LIRLowerable;
47import org.graalvm.compiler.nodes.spi.LoweringTool;
48import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
49import org.graalvm.compiler.nodes.spi.UncheckedInterfaceProvider;
50import org.graalvm.compiler.nodes.util.GraphUtil;
51
52import jdk.vm.ci.meta.JavaKind;
53
54/**
55 * The {@code InvokeNode} represents all kinds of method calls.
56 */
57// @formatter:off
58@NodeInfo(nameTemplate = "Invoke#{p#targetMethod/s}",
59          allowedUsageTypes = {Memory},
60          cycles = CYCLES_UNKNOWN,
61          cyclesRationale = "We cannot estimate the runtime cost of a call, it is a blackhole." +
62                            "However, we can estimate, dyanmically, the cost of the call operation itself based on the type of the call.",
63          size = SIZE_UNKNOWN,
64          sizeRationale = "We can only dyanmically, based on the type of the call (special, static, virtual, interface) decide" +
65                          "how much code is generated for the call.")
66// @formatter:on
67public final class InvokeNode extends AbstractMemoryCheckpoint implements Invoke, LIRLowerable, MemoryCheckpoint.Single, UncheckedInterfaceProvider {
68    public static final NodeClass<InvokeNode> TYPE = NodeClass.create(InvokeNode.class);
69
70    @OptionalInput ValueNode classInit;
71    @Input(Extension) CallTargetNode callTarget;
72    @OptionalInput(State) FrameState stateDuring;
73    @OptionalInput(Guard) GuardingNode guard;
74    protected final int bci;
75    protected boolean polymorphic;
76    protected boolean useForInlining;
77
78    public InvokeNode(CallTargetNode callTarget, int bci) {
79        this(callTarget, bci, callTarget.returnStamp().getTrustedStamp());
80    }
81
82    public InvokeNode(CallTargetNode callTarget, int bci, Stamp stamp) {
83        super(TYPE, stamp);
84        this.callTarget = callTarget;
85        this.bci = bci;
86        this.polymorphic = false;
87        this.useForInlining = true;
88    }
89
90    @Override
91    public CallTargetNode callTarget() {
92        return callTarget;
93    }
94
95    void setCallTarget(CallTargetNode callTarget) {
96        updateUsages(this.callTarget, callTarget);
97        this.callTarget = callTarget;
98    }
99
100    @Override
101    public boolean isPolymorphic() {
102        return polymorphic;
103    }
104
105    @Override
106    public void setPolymorphic(boolean value) {
107        this.polymorphic = value;
108    }
109
110    @Override
111    public boolean useForInlining() {
112        return useForInlining;
113    }
114
115    @Override
116    public void setUseForInlining(boolean value) {
117        this.useForInlining = value;
118    }
119
120    @Override
121    public boolean isAllowedUsageType(InputType type) {
122        if (!super.isAllowedUsageType(type)) {
123            if (getStackKind() != JavaKind.Void) {
124                if (callTarget instanceof MethodCallTargetNode && ((MethodCallTargetNode) callTarget).targetMethod().getAnnotation(NodeIntrinsic.class) != null) {
125                    return true;
126                }
127            }
128            return false;
129        }
130        return true;
131    }
132
133    @Override
134    public Map<Object, Object> getDebugProperties(Map<Object, Object> map) {
135        Map<Object, Object> debugProperties = super.getDebugProperties(map);
136        if (callTarget != null) {
137            debugProperties.put("targetMethod", callTarget.targetName());
138        }
139        return debugProperties;
140    }
141
142    @Override
143    public LocationIdentity getLocationIdentity() {
144        return LocationIdentity.any();
145    }
146
147    @Override
148    public void lower(LoweringTool tool) {
149        tool.getLowerer().lower(this, tool);
150    }
151
152    @Override
153    public void generate(NodeLIRBuilderTool gen) {
154        gen.emitInvoke(this);
155    }
156
157    @Override
158    public String toString(Verbosity verbosity) {
159        if (verbosity == Verbosity.Long) {
160            return super.toString(Verbosity.Short) + "(bci=" + bci() + ")";
161        } else if (verbosity == Verbosity.Name) {
162            return "Invoke#" + (callTarget == null ? "null" : callTarget().targetName());
163        } else {
164            return super.toString(verbosity);
165        }
166    }
167
168    @Override
169    public int bci() {
170        return bci;
171    }
172
173    @Override
174    public void intrinsify(Node node) {
175        assert !(node instanceof ValueNode) || node.isAllowedUsageType(InputType.Value) == isAllowedUsageType(InputType.Value) : "replacing " + this + " with " + node;
176        CallTargetNode call = callTarget;
177        FrameState currentStateAfter = stateAfter();
178        if (node instanceof StateSplit) {
179            StateSplit stateSplit = (StateSplit) node;
180            stateSplit.setStateAfter(currentStateAfter);
181        }
182        if (node instanceof ForeignCallNode) {
183            ForeignCallNode foreign = (ForeignCallNode) node;
184            foreign.setBci(bci());
185        }
186        if (node instanceof FixedWithNextNode) {
187            graph().replaceFixedWithFixed(this, (FixedWithNextNode) node);
188        } else if (node instanceof ControlSinkNode) {
189            this.replaceAtPredecessor(node);
190            this.replaceAtUsages(null);
191            GraphUtil.killCFG(this);
192            return;
193        } else {
194            graph().replaceFixed(this, node);
195        }
196        GraphUtil.killWithUnusedFloatingInputs(call);
197        if (currentStateAfter.hasNoUsages()) {
198            GraphUtil.killWithUnusedFloatingInputs(currentStateAfter);
199        }
200    }
201
202    @Override
203    public boolean canDeoptimize() {
204        return true;
205    }
206
207    @Override
208    public FrameState stateDuring() {
209        return stateDuring;
210    }
211
212    @Override
213    public void setStateDuring(FrameState stateDuring) {
214        updateUsages(this.stateDuring, stateDuring);
215        this.stateDuring = stateDuring;
216    }
217
218    @Override
219    public GuardingNode getGuard() {
220        return guard;
221    }
222
223    @Override
224    public void setGuard(GuardingNode guard) {
225        updateUsagesInterface(this.guard, guard);
226        this.guard = guard;
227    }
228
229    @Override
230    public Stamp uncheckedStamp() {
231        return this.callTarget.returnStamp().getUncheckedStamp();
232    }
233
234    @Override
235    public void setClassInit(ValueNode classInit) {
236        this.classInit = classInit;
237        updateUsages(null, classInit);
238    }
239
240    @Override
241    public ValueNode classInit() {
242        return classInit;
243    }
244}
245