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 }