1 /* 2 * Copyright (c) 2009, 2018, 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.InputType.Memory; 29 import static org.graalvm.compiler.nodeinfo.InputType.State; 30 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2; 31 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_64; 32 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8; 33 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN; 34 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2; 35 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_64; 36 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8; 37 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN; 38 39 import java.util.Map; 40 41 import org.graalvm.compiler.core.common.type.Stamp; 42 import org.graalvm.compiler.graph.Node; 43 import org.graalvm.compiler.graph.NodeClass; 44 import org.graalvm.compiler.nodeinfo.InputType; 45 import org.graalvm.compiler.nodeinfo.NodeCycles; 46 import org.graalvm.compiler.nodeinfo.NodeInfo; 47 import org.graalvm.compiler.nodeinfo.NodeSize; 48 import org.graalvm.compiler.nodeinfo.Verbosity; 49 import org.graalvm.compiler.nodes.java.MethodCallTargetNode; 50 import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint; 51 import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; 52 import org.graalvm.compiler.nodes.spi.LIRLowerable; 53 import org.graalvm.compiler.nodes.spi.LoweringTool; 54 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; 55 import org.graalvm.compiler.nodes.spi.UncheckedInterfaceProvider; 56 import jdk.internal.vm.compiler.word.LocationIdentity; 57 58 import jdk.vm.ci.code.BytecodeFrame; 59 import jdk.vm.ci.meta.JavaKind; 60 61 /** 62 * The {@code InvokeNode} represents all kinds of method calls. 63 */ 64 // @formatter:off 65 @NodeInfo(nameTemplate = "Invoke#{p#targetMethod/s}", 66 allowedUsageTypes = {Memory}, 67 cycles = CYCLES_UNKNOWN, 68 cyclesRationale = "We cannot estimate the runtime cost of a call, it is a blackhole." + 69 "However, we can estimate, dynamically, the cost of the call operation itself based on the type of the call.", 70 size = SIZE_UNKNOWN, 71 sizeRationale = "We can only dynamically, based on the type of the call (special, static, virtual, interface) decide" + 72 "how much code is generated for the call.") 73 // @formatter:on 74 public final class InvokeNode extends AbstractMemoryCheckpoint implements Invoke, LIRLowerable, MemoryCheckpoint.Single, UncheckedInterfaceProvider { 75 public static final NodeClass<InvokeNode> TYPE = NodeClass.create(InvokeNode.class); 76 77 @OptionalInput ValueNode classInit; 78 @Input(Extension) CallTargetNode callTarget; 79 @OptionalInput(State) FrameState stateDuring; 80 protected int bci; 81 protected boolean polymorphic; 82 protected boolean useForInlining; 83 protected final LocationIdentity identity; 84 85 public InvokeNode(CallTargetNode callTarget, int bci) { 86 this(callTarget, bci, callTarget.returnStamp().getTrustedStamp()); 87 } 88 89 public InvokeNode(CallTargetNode callTarget, int bci, LocationIdentity identity) { 90 this(callTarget, bci, callTarget.returnStamp().getTrustedStamp(), identity); 91 } 92 93 public InvokeNode(CallTargetNode callTarget, int bci, Stamp stamp) { 94 this(callTarget, bci, stamp, LocationIdentity.any()); 95 } 96 97 public InvokeNode(CallTargetNode callTarget, int bci, Stamp stamp, LocationIdentity identity) { 98 super(TYPE, stamp); 99 this.callTarget = callTarget; 100 this.bci = bci; 101 this.polymorphic = false; 102 this.useForInlining = true; 103 this.identity = identity; 104 } 105 106 public InvokeNode(InvokeWithExceptionNode invoke) { 107 super(TYPE, invoke.stamp); 108 this.callTarget = invoke.callTarget; 109 this.bci = invoke.bci; 110 this.polymorphic = invoke.polymorphic; 111 this.useForInlining = invoke.useForInlining; 112 this.identity = invoke.getLocationIdentity(); 113 } 114 115 @Override 116 public void replaceBci(int newBci) { 117 assert BytecodeFrame.isPlaceholderBci(bci) && !BytecodeFrame.isPlaceholderBci(newBci) : "can only replace placeholder with better bci"; 118 bci = newBci; 119 } 120 121 @Override 122 protected void afterClone(Node other) { 123 updateInliningLogAfterClone(other); 124 } 125 126 @Override 127 public FixedNode asFixedNode() { 128 return this; 129 } 130 131 @Override 132 public CallTargetNode callTarget() { 133 return callTarget; 134 } 135 136 void setCallTarget(CallTargetNode callTarget) { 137 updateUsages(this.callTarget, callTarget); 138 this.callTarget = callTarget; 139 } 140 141 @Override 142 public boolean isPolymorphic() { 143 return polymorphic; 144 } 145 146 @Override 147 public void setPolymorphic(boolean value) { 148 this.polymorphic = value; 149 } 150 151 @Override 152 public boolean useForInlining() { 153 return useForInlining; 154 } 155 156 @Override 157 public void setUseForInlining(boolean value) { 158 this.useForInlining = value; 159 } 160 161 @Override 162 public boolean isAllowedUsageType(InputType type) { 163 if (!super.isAllowedUsageType(type)) { 164 if (getStackKind() != JavaKind.Void) { 165 if (callTarget instanceof MethodCallTargetNode && ((MethodCallTargetNode) callTarget).targetMethod().getAnnotation(NodeIntrinsic.class) != null) { 166 return true; 167 } 168 } 169 return false; 170 } 171 return true; 172 } 173 174 @Override 175 public Map<Object, Object> getDebugProperties(Map<Object, Object> map) { 176 Map<Object, Object> debugProperties = super.getDebugProperties(map); 177 if (callTarget != null) { 178 debugProperties.put("targetMethod", callTarget.targetName()); 179 } 180 return debugProperties; 181 } 182 183 @Override 184 public LocationIdentity getLocationIdentity() { 185 return identity; 186 } 187 188 @Override 189 public void lower(LoweringTool tool) { 190 tool.getLowerer().lower(this, tool); 191 } 192 193 @Override 194 public void generate(NodeLIRBuilderTool gen) { 195 gen.emitInvoke(this); 196 } 197 198 @Override 199 public String toString(Verbosity verbosity) { 200 if (verbosity == Verbosity.Long) { 201 return super.toString(Verbosity.Short) + "(bci=" + bci() + ")"; 202 } else if (verbosity == Verbosity.Name) { 203 return "Invoke#" + (callTarget == null ? "null" : callTarget().targetName()); 204 } else { 205 return super.toString(verbosity); 206 } 207 } 208 209 @Override 210 public int bci() { 211 return bci; 212 } 213 214 @Override 215 public boolean canDeoptimize() { 216 return true; 217 } 218 219 @Override 220 public FrameState stateDuring() { 221 return stateDuring; 222 } 223 224 @Override 225 public void setStateDuring(FrameState stateDuring) { 226 updateUsages(this.stateDuring, stateDuring); 227 this.stateDuring = stateDuring; 228 } 229 230 @Override 231 public Stamp uncheckedStamp() { 232 return this.callTarget.returnStamp().getUncheckedStamp(); 233 } 234 235 @Override 236 public void setClassInit(ValueNode classInit) { 237 this.classInit = classInit; 238 updateUsages(null, classInit); 239 } 240 241 @Override 242 public ValueNode classInit() { 243 return classInit; 244 } 245 246 @Override 247 public NodeCycles estimatedNodeCycles() { 248 if (callTarget == null) { 249 return CYCLES_UNKNOWN; 250 } 251 switch (callTarget.invokeKind()) { 252 case Interface: 253 return CYCLES_64; 254 case Special: 255 case Static: 256 return CYCLES_2; 257 case Virtual: 258 return CYCLES_8; 259 default: 260 return CYCLES_UNKNOWN; 261 } 262 } 263 264 @Override 265 public NodeSize estimatedNodeSize() { 266 if (callTarget == null) { 267 return SIZE_UNKNOWN; 268 } 269 switch (callTarget.invokeKind()) { 270 case Interface: 271 return SIZE_64; 272 case Special: 273 case Static: 274 return SIZE_2; 275 case Virtual: 276 return SIZE_8; 277 default: 278 return SIZE_UNKNOWN; 279 } 280 } 281 }