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 }