1 /*
   2  * Copyright (c) 2011, 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_UNKNOWN;
  31 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN;
  32 
  33 import java.util.Map;
  34 
  35 import org.graalvm.compiler.core.common.type.Stamp;
  36 import org.graalvm.compiler.debug.DebugCloseable;
  37 import org.graalvm.compiler.graph.Node;
  38 import org.graalvm.compiler.graph.NodeClass;
  39 import org.graalvm.compiler.nodeinfo.NodeInfo;
  40 import org.graalvm.compiler.nodeinfo.Verbosity;
  41 import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
  42 import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
  43 import org.graalvm.compiler.nodes.spi.LIRLowerable;
  44 import org.graalvm.compiler.nodes.spi.LoweringTool;
  45 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
  46 import org.graalvm.compiler.nodes.spi.UncheckedInterfaceProvider;
  47 import org.graalvm.compiler.nodes.util.GraphUtil;
  48 import jdk.internal.vm.compiler.word.LocationIdentity;
  49 
  50 import jdk.vm.ci.code.BytecodeFrame;
  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     protected int bci;
  65     protected boolean polymorphic;
  66     protected boolean useForInlining;
  67     protected double exceptionProbability;
  68 
  69     public InvokeWithExceptionNode(CallTargetNode callTarget, AbstractBeginNode exceptionEdge, int bci) {
  70         super(TYPE, callTarget.returnStamp().getTrustedStamp());
  71         this.exceptionEdge = exceptionEdge;
  72         this.bci = bci;
  73         this.callTarget = callTarget;
  74         this.polymorphic = false;
  75         this.useForInlining = true;
  76         this.exceptionProbability = EXCEPTION_PROBA;
  77     }
  78 
  79     @Override
  80     protected void afterClone(Node other) {
  81         updateInliningLogAfterClone(other);
  82     }
  83 
  84     @Override
  85     public FixedNode asFixedNode() {
  86         return this;
  87     }
  88 
  89     public AbstractBeginNode exceptionEdge() {
  90         return exceptionEdge;
  91     }
  92 
  93     public void setExceptionEdge(AbstractBeginNode x) {
  94         updatePredecessor(exceptionEdge, x);
  95         exceptionEdge = x;
  96     }
  97 
  98     @Override
  99     public AbstractBeginNode next() {
 100         return next;
 101     }
 102 
 103     public void setNext(AbstractBeginNode x) {
 104         updatePredecessor(next, x);
 105         next = x;
 106     }
 107 
 108     @Override
 109     public CallTargetNode callTarget() {
 110         return callTarget;
 111     }
 112 
 113     void setCallTarget(CallTargetNode callTarget) {
 114         updateUsages(this.callTarget, callTarget);
 115         this.callTarget = callTarget;
 116     }
 117 
 118     public MethodCallTargetNode methodCallTarget() {
 119         return (MethodCallTargetNode) callTarget;
 120     }
 121 
 122     @Override
 123     public boolean isPolymorphic() {
 124         return polymorphic;
 125     }
 126 
 127     @Override
 128     public void setPolymorphic(boolean value) {
 129         this.polymorphic = value;
 130     }
 131 
 132     @Override
 133     public boolean useForInlining() {
 134         return useForInlining;
 135     }
 136 
 137     @Override
 138     public void setUseForInlining(boolean value) {
 139         this.useForInlining = value;
 140     }
 141 
 142     @Override
 143     public String toString(Verbosity verbosity) {
 144         if (verbosity == Verbosity.Long) {
 145             return super.toString(Verbosity.Short) + "(bci=" + bci() + ")";
 146         } else if (verbosity == Verbosity.Name) {
 147             return "Invoke#" + (callTarget == null ? "null" : callTarget().targetName());
 148         } else {
 149             return super.toString(verbosity);
 150         }
 151     }
 152 
 153     @Override
 154     public int bci() {
 155         return bci;
 156     }
 157 
 158     @Override
 159     public void setNext(FixedNode x) {
 160         if (x != null) {
 161             this.setNext(KillingBeginNode.begin(x, getLocationIdentity()));
 162         } else {
 163             this.setNext(null);
 164         }
 165     }
 166 
 167     @Override
 168     public void lower(LoweringTool tool) {
 169         tool.getLowerer().lower(this, tool);
 170     }
 171 
 172     @Override
 173     public void generate(NodeLIRBuilderTool gen) {
 174         gen.emitInvoke(this);
 175     }
 176 
 177     @Override
 178     public FrameState stateAfter() {
 179         return stateAfter;
 180     }
 181 
 182     @Override
 183     public void setStateAfter(FrameState stateAfter) {
 184         updateUsages(this.stateAfter, stateAfter);
 185         this.stateAfter = stateAfter;
 186     }
 187 
 188     @Override
 189     public boolean hasSideEffect() {
 190         return true;
 191     }
 192 
 193     @Override
 194     public LocationIdentity getLocationIdentity() {
 195         return LocationIdentity.any();
 196     }
 197 
 198     @Override
 199     public Map<Object, Object> getDebugProperties(Map<Object, Object> map) {
 200         Map<Object, Object> debugProperties = super.getDebugProperties(map);
 201         if (callTarget != null) {
 202             debugProperties.put("targetMethod", callTarget.targetName());
 203         }
 204         return debugProperties;
 205     }
 206 
 207     public void killExceptionEdge() {
 208         AbstractBeginNode edge = exceptionEdge();
 209         setExceptionEdge(null);
 210         GraphUtil.killCFG(edge);
 211     }
 212 
 213     @SuppressWarnings("try")
 214     public AbstractBeginNode killKillingBegin() {
 215         AbstractBeginNode begin = next();
 216         if (begin instanceof KillingBeginNode) {
 217             try (DebugCloseable position = begin.withNodeSourcePosition()) {
 218                 AbstractBeginNode newBegin = new BeginNode();
 219                 graph().addAfterFixed(begin, graph().add(newBegin));
 220                 begin.replaceAtUsages(newBegin);
 221                 graph().removeFixed(begin);
 222                 return newBegin;
 223             }
 224         }
 225         return begin;
 226     }
 227 
 228     @Override
 229     public void replaceBci(int newBci) {
 230         assert BytecodeFrame.isPlaceholderBci(bci) && !BytecodeFrame.isPlaceholderBci(newBci) : "can only replace placeholder with better bci";
 231         bci = newBci;
 232     }
 233 
 234     @Override
 235     public double probability(AbstractBeginNode successor) {
 236         return successor == next ? 1 - exceptionProbability : exceptionProbability;
 237     }
 238 
 239     @Override
 240     public boolean canDeoptimize() {
 241         return true;
 242     }
 243 
 244     @Override
 245     public FrameState stateDuring() {
 246         return stateDuring;
 247     }
 248 
 249     @Override
 250     public void setStateDuring(FrameState stateDuring) {
 251         updateUsages(this.stateDuring, stateDuring);
 252         this.stateDuring = stateDuring;
 253     }
 254 
 255     @Override
 256     public AbstractBeginNode getPrimarySuccessor() {
 257         return this.next();
 258     }
 259 
 260     @Override
 261     public Stamp uncheckedStamp() {
 262         return this.callTarget.returnStamp().getUncheckedStamp();
 263     }
 264 
 265     @Override
 266     public void setClassInit(ValueNode classInit) {
 267         this.classInit = classInit;
 268         updateUsages(null, classInit);
 269     }
 270 
 271     @Override
 272     public ValueNode classInit() {
 273         return classInit;
 274     }
 275 
 276     @Override
 277     public boolean setProbability(AbstractBeginNode successor, double value) {
 278         // Cannot set probability for exception invokes.
 279         return false;
 280     }
 281 
 282     @Override
 283     public int getSuccessorCount() {
 284         return 2;
 285     }
 286 
 287     /**
 288      * Replaces this InvokeWithExceptionNode with a normal InvokeNode. Kills the exception dispatch
 289      * code.
 290      */
 291     public InvokeNode replaceWithInvoke() {
 292         InvokeNode newInvoke = graph().add(new InvokeNode(callTarget, bci, stamp, getLocationIdentity()));
 293         newInvoke.setStateAfter(stateAfter);
 294         newInvoke.setStateDuring(stateDuring);
 295         AbstractBeginNode oldException = this.exceptionEdge;
 296         graph().replaceSplitWithFixed(this, newInvoke, this.next());
 297         GraphUtil.killCFG(oldException);
 298         return newInvoke;
 299     }
 300 }