1 /*
   2  * Copyright (c) 2011, 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.NodeInfo;
  39 import org.graalvm.compiler.nodeinfo.Verbosity;
  40 import org.graalvm.compiler.nodes.extended.ForeignCallNode;
  41 import org.graalvm.compiler.nodes.extended.GuardingNode;
  42 import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
  43 import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
  44 import org.graalvm.compiler.nodes.spi.LIRLowerable;
  45 import org.graalvm.compiler.nodes.spi.LoweringTool;
  46 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
  47 import org.graalvm.compiler.nodes.spi.UncheckedInterfaceProvider;
  48 import org.graalvm.compiler.nodes.util.GraphUtil;
  49 
  50 import jdk.vm.ci.meta.JavaKind;
  51 
  52 @NodeInfo(nameTemplate = "Invoke!#{p#targetMethod/s}", allowedUsageTypes = {Memory}, cycles = CYCLES_UNKNOWN, size = SIZE_UNKNOWN)
  53 public final class InvokeWithExceptionNode extends ControlSplitNode implements Invoke, MemoryCheckpoint.Single, LIRLowerable, UncheckedInterfaceProvider {
  54     public static final NodeClass<InvokeWithExceptionNode> TYPE = NodeClass.create(InvokeWithExceptionNode.class);
  55 
  56     private static final double EXCEPTION_PROBA = 1e-5;
  57 
  58     @Successor AbstractBeginNode next;
  59     @Successor AbstractBeginNode exceptionEdge;
  60     @OptionalInput ValueNode classInit;
  61     @Input(Extension) CallTargetNode callTarget;
  62     @OptionalInput(State) FrameState stateDuring;
  63     @OptionalInput(State) FrameState stateAfter;
  64     @OptionalInput(Guard) GuardingNode guard;
  65     protected final int bci;
  66     protected boolean polymorphic;
  67     protected boolean useForInlining;
  68     protected double exceptionProbability;
  69 
  70     public InvokeWithExceptionNode(CallTargetNode callTarget, AbstractBeginNode exceptionEdge, int bci) {
  71         super(TYPE, callTarget.returnStamp().getTrustedStamp());
  72         this.exceptionEdge = exceptionEdge;
  73         this.bci = bci;
  74         this.callTarget = callTarget;
  75         this.polymorphic = false;
  76         this.useForInlining = true;
  77         this.exceptionProbability = EXCEPTION_PROBA;
  78     }
  79 
  80     public AbstractBeginNode exceptionEdge() {
  81         return exceptionEdge;
  82     }
  83 
  84     public void setExceptionEdge(AbstractBeginNode x) {
  85         updatePredecessor(exceptionEdge, x);
  86         exceptionEdge = x;
  87     }
  88 
  89     @Override
  90     public AbstractBeginNode next() {
  91         return next;
  92     }
  93 
  94     public void setNext(AbstractBeginNode x) {
  95         updatePredecessor(next, x);
  96         next = x;
  97     }
  98 
  99     @Override
 100     public CallTargetNode callTarget() {
 101         return callTarget;
 102     }
 103 
 104     void setCallTarget(CallTargetNode callTarget) {
 105         updateUsages(this.callTarget, callTarget);
 106         this.callTarget = callTarget;
 107     }
 108 
 109     public MethodCallTargetNode methodCallTarget() {
 110         return (MethodCallTargetNode) callTarget;
 111     }
 112 
 113     @Override
 114     public boolean isPolymorphic() {
 115         return polymorphic;
 116     }
 117 
 118     @Override
 119     public void setPolymorphic(boolean value) {
 120         this.polymorphic = value;
 121     }
 122 
 123     @Override
 124     public boolean useForInlining() {
 125         return useForInlining;
 126     }
 127 
 128     @Override
 129     public void setUseForInlining(boolean value) {
 130         this.useForInlining = value;
 131     }
 132 
 133     @Override
 134     public String toString(Verbosity verbosity) {
 135         if (verbosity == Verbosity.Long) {
 136             return super.toString(Verbosity.Short) + "(bci=" + bci() + ")";
 137         } else if (verbosity == Verbosity.Name) {
 138             return "Invoke#" + (callTarget == null ? "null" : callTarget().targetName());
 139         } else {
 140             return super.toString(verbosity);
 141         }
 142     }
 143 
 144     @Override
 145     public int bci() {
 146         return bci;
 147     }
 148 
 149     @Override
 150     public void setNext(FixedNode x) {
 151         if (x != null) {
 152             this.setNext(KillingBeginNode.begin(x, getLocationIdentity()));
 153         } else {
 154             this.setNext(null);
 155         }
 156     }
 157 
 158     @Override
 159     public void lower(LoweringTool tool) {
 160         tool.getLowerer().lower(this, tool);
 161     }
 162 
 163     @Override
 164     public void generate(NodeLIRBuilderTool gen) {
 165         gen.emitInvoke(this);
 166     }
 167 
 168     @Override
 169     public FrameState stateAfter() {
 170         return stateAfter;
 171     }
 172 
 173     @Override
 174     public void setStateAfter(FrameState stateAfter) {
 175         updateUsages(this.stateAfter, stateAfter);
 176         this.stateAfter = stateAfter;
 177     }
 178 
 179     @Override
 180     public boolean hasSideEffect() {
 181         return true;
 182     }
 183 
 184     @Override
 185     public LocationIdentity getLocationIdentity() {
 186         return LocationIdentity.any();
 187     }
 188 
 189     @Override
 190     public Map<Object, Object> getDebugProperties(Map<Object, Object> map) {
 191         Map<Object, Object> debugProperties = super.getDebugProperties(map);
 192         if (callTarget != null) {
 193             debugProperties.put("targetMethod", callTarget.targetName());
 194         }
 195         return debugProperties;
 196     }
 197 
 198     public void killExceptionEdge() {
 199         AbstractBeginNode edge = exceptionEdge();
 200         setExceptionEdge(null);
 201         GraphUtil.killCFG(edge);
 202     }
 203 
 204     @Override
 205     public void intrinsify(Node node) {
 206         assert !(node instanceof ValueNode) || (((ValueNode) node).getStackKind() == JavaKind.Void) == (getStackKind() == JavaKind.Void);
 207         CallTargetNode call = callTarget;
 208         FrameState state = stateAfter();
 209         killExceptionEdge();
 210         if (node instanceof StateSplit) {
 211             StateSplit stateSplit = (StateSplit) node;
 212             stateSplit.setStateAfter(state);
 213         }
 214         if (node instanceof ForeignCallNode) {
 215             ForeignCallNode foreign = (ForeignCallNode) node;
 216             foreign.setBci(bci());
 217         }
 218         if (node == null) {
 219             assert getStackKind() == JavaKind.Void && hasNoUsages();
 220             graph().removeSplit(this, next());
 221         } else if (node instanceof ControlSinkNode) {
 222             this.replaceAtPredecessor(node);
 223             this.replaceAtUsages(null);
 224             GraphUtil.killCFG(this);
 225             return;
 226         } else {
 227             graph().replaceSplit(this, node, next());
 228         }
 229         GraphUtil.killWithUnusedFloatingInputs(call);
 230         if (state.hasNoUsages()) {
 231             GraphUtil.killWithUnusedFloatingInputs(state);
 232         }
 233     }
 234 
 235     @Override
 236     public double probability(AbstractBeginNode successor) {
 237         return successor == next ? 1 - exceptionProbability : exceptionProbability;
 238     }
 239 
 240     @Override
 241     public boolean canDeoptimize() {
 242         return true;
 243     }
 244 
 245     @Override
 246     public FrameState stateDuring() {
 247         return stateDuring;
 248     }
 249 
 250     @Override
 251     public void setStateDuring(FrameState stateDuring) {
 252         updateUsages(this.stateDuring, stateDuring);
 253         this.stateDuring = stateDuring;
 254     }
 255 
 256     @Override
 257     public GuardingNode getGuard() {
 258         return guard;
 259     }
 260 
 261     @Override
 262     public void setGuard(GuardingNode guard) {
 263         updateUsagesInterface(this.guard, guard);
 264         this.guard = guard;
 265     }
 266 
 267     @Override
 268     public AbstractBeginNode getPrimarySuccessor() {
 269         return this.next();
 270     }
 271 
 272     @Override
 273     public Stamp uncheckedStamp() {
 274         return this.callTarget.returnStamp().getUncheckedStamp();
 275     }
 276 
 277     @Override
 278     public void setClassInit(ValueNode classInit) {
 279         this.classInit = classInit;
 280         updateUsages(null, classInit);
 281     }
 282 
 283     @Override
 284     public ValueNode classInit() {
 285         return classInit;
 286     }
 287 }