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