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 }