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