1 /*
   2  * Copyright (c) 2011, 2019, 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.IterableNodeType;
  38 import org.graalvm.compiler.graph.Node;
  39 import org.graalvm.compiler.graph.NodeClass;
  40 import org.graalvm.compiler.nodeinfo.NodeInfo;
  41 import org.graalvm.compiler.nodeinfo.Verbosity;
  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 import jdk.internal.vm.compiler.word.LocationIdentity;
  50 
  51 import jdk.vm.ci.code.BytecodeFrame;
  52 
  53 @NodeInfo(nameTemplate = "Invoke!#{p#targetMethod/s}", allowedUsageTypes = {Memory}, cycles = CYCLES_UNKNOWN, size = SIZE_UNKNOWN)
  54 public final class InvokeWithExceptionNode extends ControlSplitNode implements Invoke, IterableNodeType, MemoryCheckpoint.Single, LIRLowerable, UncheckedInterfaceProvider {
  55     public static final NodeClass<InvokeWithExceptionNode> TYPE = NodeClass.create(InvokeWithExceptionNode.class);
  56 
  57     private static final double EXCEPTION_PROBA = 1e-5;
  58 
  59     @Successor AbstractBeginNode next;
  60     @Successor AbstractBeginNode exceptionEdge;
  61     @OptionalInput ValueNode classInit;
  62     @Input(Extension) CallTargetNode callTarget;
  63     @OptionalInput(State) FrameState stateDuring;
  64     @OptionalInput(State) FrameState stateAfter;
  65     protected 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     @Override
  81     protected void afterClone(Node other) {
  82         updateInliningLogAfterClone(other);
  83     }
  84 
  85     @Override
  86     public FixedNode asFixedNode() {
  87         return this;
  88     }
  89 
  90     public AbstractBeginNode exceptionEdge() {
  91         return exceptionEdge;
  92     }
  93 
  94     public void setExceptionEdge(AbstractBeginNode x) {
  95         updatePredecessor(exceptionEdge, x);
  96         exceptionEdge = x;
  97     }
  98 
  99     @Override
 100     public AbstractBeginNode next() {
 101         return next;
 102     }
 103 
 104     public void setNext(AbstractBeginNode x) {
 105         updatePredecessor(next, x);
 106         next = x;
 107     }
 108 
 109     @Override
 110     public CallTargetNode callTarget() {
 111         return callTarget;
 112     }
 113 
 114     void setCallTarget(CallTargetNode callTarget) {
 115         updateUsages(this.callTarget, callTarget);
 116         this.callTarget = callTarget;
 117     }
 118 
 119     public MethodCallTargetNode methodCallTarget() {
 120         return (MethodCallTargetNode) callTarget;
 121     }
 122 
 123     @Override
 124     public boolean isPolymorphic() {
 125         return polymorphic;
 126     }
 127 
 128     @Override
 129     public void setPolymorphic(boolean value) {
 130         this.polymorphic = value;
 131     }
 132 
 133     @Override
 134     public boolean useForInlining() {
 135         return useForInlining;
 136     }
 137 
 138     @Override
 139     public void setUseForInlining(boolean value) {
 140         this.useForInlining = value;
 141     }
 142 
 143     @Override
 144     public String toString(Verbosity verbosity) {
 145         if (verbosity == Verbosity.Long) {
 146             return super.toString(Verbosity.Short) + "(bci=" + bci() + ")";
 147         } else if (verbosity == Verbosity.Name) {
 148             return "Invoke#" + (callTarget == null ? "null" : callTarget().targetName());
 149         } else {
 150             return super.toString(verbosity);
 151         }
 152     }
 153 
 154     @Override
 155     public int bci() {
 156         return bci;
 157     }
 158 
 159     @Override
 160     public void setNext(FixedNode x) {
 161         if (x != null) {
 162             this.setNext(KillingBeginNode.begin(x, getLocationIdentity()));
 163         } else {
 164             this.setNext(null);
 165         }
 166     }
 167 
 168     @Override
 169     public void lower(LoweringTool tool) {
 170         tool.getLowerer().lower(this, tool);
 171     }
 172 
 173     @Override
 174     public void generate(NodeLIRBuilderTool gen) {
 175         gen.emitInvoke(this);
 176     }
 177 
 178     @Override
 179     public FrameState stateAfter() {
 180         return stateAfter;
 181     }
 182 
 183     @Override
 184     public void setStateAfter(FrameState stateAfter) {
 185         updateUsages(this.stateAfter, stateAfter);
 186         this.stateAfter = stateAfter;
 187     }
 188 
 189     @Override
 190     public boolean hasSideEffect() {
 191         return true;
 192     }
 193 
 194     @Override
 195     public LocationIdentity getLocationIdentity() {
 196         return LocationIdentity.any();
 197     }
 198 
 199     @Override
 200     public Map<Object, Object> getDebugProperties(Map<Object, Object> map) {
 201         Map<Object, Object> debugProperties = super.getDebugProperties(map);
 202         if (callTarget != null) {
 203             debugProperties.put("targetMethod", callTarget.targetName());
 204         }
 205         return debugProperties;
 206     }
 207 
 208     public void killExceptionEdge() {
 209         AbstractBeginNode edge = exceptionEdge();
 210         setExceptionEdge(null);
 211         GraphUtil.killCFG(edge);
 212     }
 213 
 214     @SuppressWarnings("try")
 215     public AbstractBeginNode killKillingBegin() {
 216         AbstractBeginNode begin = next();
 217         if (begin instanceof KillingBeginNode) {
 218             try (DebugCloseable position = begin.withNodeSourcePosition()) {
 219                 AbstractBeginNode newBegin = new BeginNode();
 220                 graph().addAfterFixed(begin, graph().add(newBegin));
 221                 begin.replaceAtUsages(newBegin);
 222                 graph().removeFixed(begin);
 223                 return newBegin;
 224             }
 225         }
 226         return begin;
 227     }
 228 
 229     @Override
 230     public void replaceBci(int newBci) {
 231         assert BytecodeFrame.isPlaceholderBci(bci) && !BytecodeFrame.isPlaceholderBci(newBci) : "can only replace placeholder with better bci";
 232         bci = newBci;
 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 AbstractBeginNode getPrimarySuccessor() {
 258         return this.next();
 259     }
 260 
 261     @Override
 262     public Stamp uncheckedStamp() {
 263         return this.callTarget.returnStamp().getUncheckedStamp();
 264     }
 265 
 266     @Override
 267     public void setClassInit(ValueNode classInit) {
 268         this.classInit = classInit;
 269         updateUsages(null, classInit);
 270     }
 271 
 272     @Override
 273     public ValueNode classInit() {
 274         return classInit;
 275     }
 276 
 277     @Override
 278     public boolean setProbability(AbstractBeginNode successor, double value) {
 279         // Cannot set probability for exception invokes.
 280         return false;
 281     }
 282 
 283     @Override
 284     public int getSuccessorCount() {
 285         return 2;
 286     }
 287 
 288     /**
 289      * Replaces this InvokeWithExceptionNode with a normal InvokeNode. Kills the exception dispatch
 290      * code.
 291      */
 292     public InvokeNode replaceWithInvoke() {
 293         InvokeNode newInvoke = graph().add(new InvokeNode(callTarget, bci, stamp, getLocationIdentity()));
 294         newInvoke.setStateAfter(stateAfter);
 295         newInvoke.setStateDuring(stateDuring);
 296         AbstractBeginNode oldException = this.exceptionEdge;
 297         graph().replaceSplitWithFixed(this, newInvoke, this.next());
 298         GraphUtil.killCFG(oldException);
 299         return newInvoke;
 300     }
 301 }