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