1 /*
2  * Copyright (c) 2011, 2019, 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  */
23 
24 
25 package org.graalvm.compiler.nodes;
26 
27 import static org.graalvm.compiler.nodeinfo.InputType.Extension;
28 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
29 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
30 
31 import org.graalvm.compiler.core.common.type.Stamp;
32 import org.graalvm.compiler.core.common.type.StampFactory;
33 import org.graalvm.compiler.core.common.type.StampPair;
34 import org.graalvm.compiler.core.common.type.TypeReference;
35 import org.graalvm.compiler.graph.NodeClass;
36 import org.graalvm.compiler.graph.NodeInputList;
37 import org.graalvm.compiler.nodeinfo.NodeInfo;
38 import org.graalvm.compiler.nodes.spi.LIRLowerable;
39 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
40 
41 import jdk.vm.ci.meta.Assumptions;
42 import jdk.vm.ci.meta.JavaKind;
43 import jdk.vm.ci.meta.JavaType;
44 import jdk.vm.ci.meta.ResolvedJavaMethod;
45 import jdk.vm.ci.meta.ResolvedJavaType;
46 
47 @NodeInfo(allowedUsageTypes = Extension, cycles = CYCLES_0, size = SIZE_0)
48 public abstract class CallTargetNode extends ValueNode implements LIRLowerable {
49     public static final NodeClass<CallTargetNode> TYPE = NodeClass.create(CallTargetNode.class);
50 
51     public enum InvokeKind {
52         Interface(false),
53         Special(true),
54         Static(true),
55         Virtual(false);
56 
InvokeKind(boolean direct)57         InvokeKind(boolean direct) {
58             this.direct = direct;
59         }
60 
61         private final boolean direct;
62 
hasReceiver()63         public boolean hasReceiver() {
64             return this != Static;
65         }
66 
isDirect()67         public boolean isDirect() {
68             return direct;
69         }
70 
isIndirect()71         public boolean isIndirect() {
72             return !direct;
73         }
74 
isInterface()75         public boolean isInterface() {
76             return this == InvokeKind.Interface;
77         }
78     }
79 
80     @Input protected NodeInputList<ValueNode> arguments;
81     protected ResolvedJavaMethod targetMethod;
82 
83     /**
84      * Receiver type referenced at the interface call site.
85      *
86      * We need to distinguish the declaring type from the type referenced at the call site. We must
87      * use the referenced type as lower type bound when doing CHA since interface calls must throw
88      * exception if the receiver type is not a subtype of the reference type.
89      *
90      * Example:
91      *
92      * <pre>
93      * interface I1 {
94      *     void foo();
95      * }
96      *
97      * interface I2 extends I1 {
98      * }
99      *
100      * void bar(I2 o) {
101      *     o.foo();
102      * }
103      * </pre>
104      *
105      * Here at the call site the declaring type for {@code foo()} is {@code I1}, while the
106      * referenced type is {@code I2}. Only receivers of type {@code T} that is {@code T <: I2}
107      * should be allowed at the call site. If they are not - an exception should be thrown.
108      *
109      * Since the interface types are not verified, another way to think about this call site is to
110      * rewrite it as follows:
111      *
112      * <pre>
113      * void bar(Object o) {
114      *     ((I2) o).foo();
115      * }
116      * </pre>
117      *
118      * So, in case the receiver is not a subtype of {@code I2} an exception is thrown.
119      */
120     protected ResolvedJavaType referencedType;
121 
122     protected InvokeKind invokeKind;
123     protected final StampPair returnStamp;
124 
CallTargetNode(NodeClass<? extends CallTargetNode> c, ValueNode[] arguments, ResolvedJavaMethod targetMethod, InvokeKind invokeKind, StampPair returnStamp)125     protected CallTargetNode(NodeClass<? extends CallTargetNode> c, ValueNode[] arguments, ResolvedJavaMethod targetMethod, InvokeKind invokeKind, StampPair returnStamp) {
126         super(c, StampFactory.forVoid());
127         this.targetMethod = targetMethod;
128         this.invokeKind = invokeKind;
129         this.arguments = new NodeInputList<>(this, arguments);
130         this.returnStamp = returnStamp;
131     }
132 
arguments()133     public NodeInputList<ValueNode> arguments() {
134         return arguments;
135     }
136 
createReturnStamp(Assumptions assumptions, JavaType returnType)137     public static Stamp createReturnStamp(Assumptions assumptions, JavaType returnType) {
138         JavaKind kind = returnType.getJavaKind();
139         if (kind == JavaKind.Object && returnType instanceof ResolvedJavaType) {
140             return StampFactory.object(TypeReference.create(assumptions, (ResolvedJavaType) returnType));
141         } else {
142             return StampFactory.forKind(kind);
143         }
144     }
145 
returnStamp()146     public StampPair returnStamp() {
147         return this.returnStamp;
148     }
149 
150     /**
151      * A human-readable representation of the target, used for debug printing only.
152      */
targetName()153     public abstract String targetName();
154 
155     @Override
generate(NodeLIRBuilderTool gen)156     public void generate(NodeLIRBuilderTool gen) {
157         // nop
158     }
159 
setTargetMethod(ResolvedJavaMethod targetMethod)160     public void setTargetMethod(ResolvedJavaMethod targetMethod) {
161         this.targetMethod = targetMethod;
162     }
163 
164     /**
165      * Gets the target method for this invocation instruction.
166      *
167      * @return the target method
168      */
targetMethod()169     public ResolvedJavaMethod targetMethod() {
170         return targetMethod;
171     }
172 
setReferencedType(ResolvedJavaType referencedType)173     public void setReferencedType(ResolvedJavaType referencedType) {
174         this.referencedType = referencedType;
175     }
176 
referencedType()177     public ResolvedJavaType referencedType() {
178         return referencedType;
179     }
180 
invokeKind()181     public InvokeKind invokeKind() {
182         return invokeKind;
183     }
184 
setInvokeKind(InvokeKind kind)185     public void setInvokeKind(InvokeKind kind) {
186         this.invokeKind = kind;
187     }
188 
invoke()189     public Invoke invoke() {
190         return (Invoke) this.usages().first();
191     }
192 }
193