1 /* 2 * Copyright (c) 2014, 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.replacements; 26 27 import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.INLINE_AFTER_PARSING; 28 29 import java.lang.reflect.Method; 30 import java.lang.reflect.Modifier; 31 import java.util.ArrayList; 32 import java.util.List; 33 34 import org.graalvm.compiler.core.common.CompilationIdentifier; 35 import org.graalvm.compiler.core.common.spi.ConstantFieldProvider; 36 import org.graalvm.compiler.core.common.type.StampFactory; 37 import org.graalvm.compiler.core.common.type.StampPair; 38 import org.graalvm.compiler.debug.DebugCloseable; 39 import org.graalvm.compiler.debug.DebugContext; 40 import org.graalvm.compiler.debug.GraalError; 41 import org.graalvm.compiler.graph.Graph; 42 import org.graalvm.compiler.graph.Node.ValueNumberable; 43 import org.graalvm.compiler.graph.NodeSourcePosition; 44 import org.graalvm.compiler.java.FrameStateBuilder; 45 import org.graalvm.compiler.java.GraphBuilderPhase; 46 import org.graalvm.compiler.nodes.AbstractBeginNode; 47 import org.graalvm.compiler.nodes.AbstractMergeNode; 48 import org.graalvm.compiler.nodes.BeginNode; 49 import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind; 50 import org.graalvm.compiler.nodes.EndNode; 51 import org.graalvm.compiler.nodes.FixedNode; 52 import org.graalvm.compiler.nodes.FixedWithNextNode; 53 import org.graalvm.compiler.nodes.IfNode; 54 import org.graalvm.compiler.nodes.InvokeNode; 55 import org.graalvm.compiler.nodes.InvokeWithExceptionNode; 56 import org.graalvm.compiler.nodes.KillingBeginNode; 57 import org.graalvm.compiler.nodes.LogicNode; 58 import org.graalvm.compiler.nodes.MergeNode; 59 import org.graalvm.compiler.nodes.NodeView; 60 import org.graalvm.compiler.nodes.StructuredGraph; 61 import org.graalvm.compiler.nodes.UnwindNode; 62 import org.graalvm.compiler.nodes.ValueNode; 63 import org.graalvm.compiler.nodes.calc.FloatingNode; 64 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; 65 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; 66 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderTool; 67 import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext; 68 import org.graalvm.compiler.nodes.java.ExceptionObjectNode; 69 import org.graalvm.compiler.nodes.java.MethodCallTargetNode; 70 import org.graalvm.compiler.nodes.spi.StampProvider; 71 import org.graalvm.compiler.nodes.type.StampTool; 72 import org.graalvm.compiler.phases.OptimisticOptimizations; 73 import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase; 74 import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase.Optionality; 75 import org.graalvm.compiler.phases.common.inlining.InliningUtil; 76 import org.graalvm.compiler.phases.util.Providers; 77 import org.graalvm.compiler.word.WordTypes; 78 import jdk.internal.vm.compiler.word.LocationIdentity; 79 80 import jdk.vm.ci.code.BytecodeFrame; 81 import jdk.vm.ci.meta.ConstantReflectionProvider; 82 import jdk.vm.ci.meta.JavaKind; 83 import jdk.vm.ci.meta.JavaType; 84 import jdk.vm.ci.meta.MetaAccessProvider; 85 import jdk.vm.ci.meta.ResolvedJavaMethod; 86 import jdk.vm.ci.meta.Signature; 87 88 /** 89 * A utility for manually creating a graph. This will be expanded as necessary to support all 90 * subsystems that employ manual graph creation (as opposed to {@linkplain GraphBuilderPhase 91 * bytecode parsing} based graph creation). 92 */ 93 public class GraphKit implements GraphBuilderTool { 94 95 protected final Providers providers; 96 protected final StructuredGraph graph; 97 protected final WordTypes wordTypes; 98 protected final GraphBuilderConfiguration.Plugins graphBuilderPlugins; 99 protected FixedWithNextNode lastFixedNode; 100 101 private final List<Structure> structures; 102 103 protected abstract static class Structure { 104 } 105 106 public GraphKit(DebugContext debug, ResolvedJavaMethod stubMethod, Providers providers, WordTypes wordTypes, Plugins graphBuilderPlugins, CompilationIdentifier compilationId, String name) { 107 this.providers = providers; 108 StructuredGraph.Builder builder = new StructuredGraph.Builder(debug.getOptions(), debug).compilationId(compilationId); 109 if (name != null) { 110 builder.name(name); 111 } else { 112 builder.method(stubMethod); 113 } 114 this.graph = builder.build(); 115 graph.disableUnsafeAccessTracking(); 116 if (graph.trackNodeSourcePosition()) { 117 // Set up a default value that everything constructed by GraphKit will use. 118 graph.withNodeSourcePosition(NodeSourcePosition.substitution(stubMethod)); 119 } 120 this.wordTypes = wordTypes; 121 this.graphBuilderPlugins = graphBuilderPlugins; 122 this.lastFixedNode = graph.start(); 123 124 structures = new ArrayList<>(); 125 /* 126 * Add a dummy element, so that the access of the last element never leads to an exception. 127 */ 128 structures.add(new Structure() { 129 }); 130 } 131 132 @Override 133 public StructuredGraph getGraph() { 134 return graph; 135 } 136 137 @Override 138 public ConstantReflectionProvider getConstantReflection() { 139 return providers.getConstantReflection(); 140 } 141 142 @Override 143 public ConstantFieldProvider getConstantFieldProvider() { 144 return providers.getConstantFieldProvider(); 145 } 146 147 @Override 148 public MetaAccessProvider getMetaAccess() { 149 return providers.getMetaAccess(); 150 } 151 152 @Override 153 public StampProvider getStampProvider() { 154 return providers.getStampProvider(); 155 } 156 157 @Override 158 public boolean parsingIntrinsic() { 159 return true; 160 } 161 162 /** 163 * Ensures a floating node is added to or already present in the graph via {@link Graph#unique}. 164 * 165 * @return a node similar to {@code node} if one exists, otherwise {@code node} 166 */ 167 public <T extends FloatingNode & ValueNumberable> T unique(T node) { 168 return graph.unique(changeToWord(node)); 169 } 170 171 public <T extends ValueNode> T add(T node) { 172 return graph.add(changeToWord(node)); 173 } 174 175 public <T extends ValueNode> T changeToWord(T node) { 176 if (wordTypes != null && wordTypes.isWord(node)) { 177 node.setStamp(wordTypes.getWordStamp(StampTool.typeOrNull(node))); 178 } 179 return node; 180 } 181 182 @Override 183 public <T extends ValueNode> T append(T node) { 184 T result = graph.addOrUniqueWithInputs(changeToWord(node)); 185 if (result instanceof FixedNode) { 186 updateLastFixed((FixedNode) result); 187 } 188 return result; 189 } 190 191 private void updateLastFixed(FixedNode result) { 192 assert lastFixedNode != null; 193 assert result.predecessor() == null; 194 graph.addAfterFixed(lastFixedNode, result); 195 if (result instanceof FixedWithNextNode) { 196 lastFixedNode = (FixedWithNextNode) result; 197 } else { 198 lastFixedNode = null; 199 } 200 } 201 202 public InvokeNode createInvoke(Class<?> declaringClass, String name, ValueNode... args) { 203 return createInvoke(declaringClass, name, InvokeKind.Static, null, BytecodeFrame.UNKNOWN_BCI, args); 204 } 205 206 /** 207 * Creates and appends an {@link InvokeNode} for a call to a given method with a given set of 208 * arguments. The method is looked up via reflection based on the declaring class and name. 209 * 210 * @param declaringClass the class declaring the invoked method 211 * @param name the name of the invoked method 212 * @param args the arguments to the invocation 213 */ 214 public InvokeNode createInvoke(Class<?> declaringClass, String name, InvokeKind invokeKind, FrameStateBuilder frameStateBuilder, int bci, ValueNode... args) { 215 boolean isStatic = invokeKind == InvokeKind.Static; 216 ResolvedJavaMethod method = findMethod(declaringClass, name, isStatic); 217 return createInvoke(method, invokeKind, frameStateBuilder, bci, args); 218 } 219 220 public ResolvedJavaMethod findMethod(Class<?> declaringClass, String name, boolean isStatic) { 221 ResolvedJavaMethod method = null; 222 for (Method m : declaringClass.getDeclaredMethods()) { 223 if (Modifier.isStatic(m.getModifiers()) == isStatic && m.getName().equals(name)) { 224 assert method == null : "found more than one method in " + declaringClass + " named " + name; 225 method = providers.getMetaAccess().lookupJavaMethod(m); 226 } 227 } 228 GraalError.guarantee(method != null, "Could not find %s.%s (%s)", declaringClass, name, isStatic ? "static" : "non-static"); 229 return method; 230 } 231 232 public ResolvedJavaMethod findMethod(Class<?> declaringClass, String name, Class<?>... parameterTypes) { 233 try { 234 Method m = declaringClass.getDeclaredMethod(name, parameterTypes); 235 return providers.getMetaAccess().lookupJavaMethod(m); 236 } catch (NoSuchMethodException | SecurityException e) { 237 throw new AssertionError(e); 238 } 239 } 240 241 /** 242 * Creates and appends an {@link InvokeNode} for a call to a given method with a given set of 243 * arguments. 244 */ 245 @SuppressWarnings("try") 246 public InvokeNode createInvoke(ResolvedJavaMethod method, InvokeKind invokeKind, FrameStateBuilder frameStateBuilder, int bci, ValueNode... args) { 247 try (DebugCloseable context = graph.withNodeSourcePosition(NodeSourcePosition.substitution(graph.currentNodeSourcePosition(), method))) { 248 assert method.isStatic() == (invokeKind == InvokeKind.Static); 249 Signature signature = method.getSignature(); 250 JavaType returnType = signature.getReturnType(null); 251 assert checkArgs(method, args); 252 StampPair returnStamp = graphBuilderPlugins.getOverridingStamp(this, returnType, false); 253 if (returnStamp == null) { 254 returnStamp = StampFactory.forDeclaredType(graph.getAssumptions(), returnType, false); 255 } 256 MethodCallTargetNode callTarget = graph.add(createMethodCallTarget(invokeKind, method, args, returnStamp, bci)); 257 InvokeNode invoke = append(new InvokeNode(callTarget, bci)); 258 259 if (frameStateBuilder != null) { 260 if (invoke.getStackKind() != JavaKind.Void) { 261 frameStateBuilder.push(invoke.getStackKind(), invoke); 262 } 263 invoke.setStateAfter(frameStateBuilder.create(bci, invoke)); 264 if (invoke.getStackKind() != JavaKind.Void) { 265 frameStateBuilder.pop(invoke.getStackKind()); 266 } 267 } 268 return invoke; 269 } 270 } 271 272 @SuppressWarnings("try") 273 public InvokeWithExceptionNode createInvokeWithExceptionAndUnwind(ResolvedJavaMethod method, InvokeKind invokeKind, 274 FrameStateBuilder frameStateBuilder, int invokeBci, int exceptionEdgeBci, ValueNode... args) { 275 try (DebugCloseable context = graph.withNodeSourcePosition(NodeSourcePosition.substitution(graph.currentNodeSourcePosition(), method))) { 276 InvokeWithExceptionNode result = startInvokeWithException(method, invokeKind, frameStateBuilder, invokeBci, exceptionEdgeBci, args); 277 exceptionPart(); 278 ExceptionObjectNode exception = exceptionObject(); 279 append(new UnwindNode(exception)); 280 endInvokeWithException(); 281 return result; 282 } 283 } 284 285 @SuppressWarnings("try") 286 public InvokeWithExceptionNode createInvokeWithExceptionAndUnwind(MethodCallTargetNode callTarget, FrameStateBuilder frameStateBuilder, int invokeBci, int exceptionEdgeBci) { 287 try (DebugCloseable context = graph.withNodeSourcePosition(NodeSourcePosition.substitution(graph.currentNodeSourcePosition(), callTarget.targetMethod()))) { 288 InvokeWithExceptionNode result = startInvokeWithException(callTarget, frameStateBuilder, invokeBci, exceptionEdgeBci); 289 exceptionPart(); 290 ExceptionObjectNode exception = exceptionObject(); 291 append(new UnwindNode(exception)); 292 endInvokeWithException(); 293 return result; 294 } 295 } 296 297 protected MethodCallTargetNode createMethodCallTarget(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, StampPair returnStamp, @SuppressWarnings("unused") int bci) { 298 return new MethodCallTargetNode(invokeKind, targetMethod, args, returnStamp, null); 299 } 300 301 protected final JavaKind asKind(JavaType type) { 302 return wordTypes != null ? wordTypes.asKind(type) : type.getJavaKind(); 303 } 304 305 /** 306 * Determines if a given set of arguments is compatible with the signature of a given method. 307 * 308 * @return true if {@code args} are compatible with the signature if {@code method} 309 * @throws AssertionError if {@code args} are not compatible with the signature if 310 * {@code method} 311 */ 312 public boolean checkArgs(ResolvedJavaMethod method, ValueNode... args) { 313 Signature signature = method.getSignature(); 314 boolean isStatic = method.isStatic(); 315 if (signature.getParameterCount(!isStatic) != args.length) { 316 throw new AssertionError(graph + ": wrong number of arguments to " + method); 317 } 318 int argIndex = 0; 319 if (!isStatic) { 320 JavaKind expected = asKind(method.getDeclaringClass()); 321 JavaKind actual = args[argIndex++].stamp(NodeView.DEFAULT).getStackKind(); 322 assert expected == actual : graph + ": wrong kind of value for receiver argument of call to " + method + " [" + actual + " != " + expected + "]"; 323 } 324 for (int i = 0; i != signature.getParameterCount(false); i++) { 325 JavaKind expected = asKind(signature.getParameterType(i, method.getDeclaringClass())).getStackKind(); 326 JavaKind actual = args[argIndex++].stamp(NodeView.DEFAULT).getStackKind(); 327 if (expected != actual) { 328 throw new AssertionError(graph + ": wrong kind of value for argument " + i + " of call to " + method + " [" + actual + " != " + expected + "]"); 329 } 330 } 331 return true; 332 } 333 334 /** 335 * Recursively {@linkplain #inline inlines} all invocations currently in the graph. 336 */ 337 public void inlineInvokes(String reason, String phase) { 338 while (!graph.getNodes().filter(InvokeNode.class).isEmpty()) { 339 for (InvokeNode invoke : graph.getNodes().filter(InvokeNode.class).snapshot()) { 340 inline(invoke, reason, phase); 341 } 342 } 343 344 // Clean up all code that is now dead after inlining. 345 new DeadCodeEliminationPhase().apply(graph); 346 } 347 348 /** 349 * Inlines a given invocation to a method. The graph of the inlined method is processed in the 350 * same manner as for snippets and method substitutions. 351 */ 352 public void inline(InvokeNode invoke, String reason, String phase) { 353 ResolvedJavaMethod method = ((MethodCallTargetNode) invoke.callTarget()).targetMethod(); 354 355 MetaAccessProvider metaAccess = providers.getMetaAccess(); 356 Plugins plugins = new Plugins(graphBuilderPlugins); 357 GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(plugins); 358 359 StructuredGraph calleeGraph = new StructuredGraph.Builder(invoke.getOptions(), invoke.getDebug()).method(method).trackNodeSourcePosition(invoke.graph().trackNodeSourcePosition()).build(); 360 IntrinsicContext initialReplacementContext = new IntrinsicContext(method, method, providers.getReplacements().getDefaultReplacementBytecodeProvider(), INLINE_AFTER_PARSING); 361 GraphBuilderPhase.Instance instance = createGraphBuilderInstance(metaAccess, providers.getStampProvider(), providers.getConstantReflection(), providers.getConstantFieldProvider(), config, 362 OptimisticOptimizations.NONE, 363 initialReplacementContext); 364 instance.apply(calleeGraph); 365 366 // Remove all frame states from inlinee 367 calleeGraph.clearAllStateAfter(); 368 new DeadCodeEliminationPhase(Optionality.Required).apply(calleeGraph); 369 370 InliningUtil.inline(invoke, calleeGraph, false, method, reason, phase); 371 } 372 373 protected GraphBuilderPhase.Instance createGraphBuilderInstance(MetaAccessProvider metaAccess, StampProvider stampProvider, ConstantReflectionProvider constantReflection, 374 ConstantFieldProvider constantFieldProvider, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext) { 375 return new GraphBuilderPhase.Instance(metaAccess, stampProvider, constantReflection, constantFieldProvider, graphBuilderConfig, optimisticOpts, initialIntrinsicContext); 376 } 377 378 protected void pushStructure(Structure structure) { 379 structures.add(structure); 380 } 381 382 protected <T extends Structure> T getTopStructure(Class<T> expectedClass) { 383 return expectedClass.cast(structures.get(structures.size() - 1)); 384 } 385 386 protected void popStructure() { 387 structures.remove(structures.size() - 1); 388 } 389 390 protected enum IfState { 391 CONDITION, 392 THEN_PART, 393 ELSE_PART, 394 FINISHED 395 } 396 397 static class IfStructure extends Structure { 398 protected IfState state; 399 protected FixedNode thenPart; 400 protected FixedNode elsePart; 401 } 402 403 /** 404 * Starts an if-block. This call can be followed by a call to {@link #thenPart} to start 405 * emitting the code executed when the condition hold; and a call to {@link #elsePart} to start 406 * emititng the code when the condition does not hold. It must be followed by a call to 407 * {@link #endIf} to close the if-block. 408 * 409 * @param condition The condition for the if-block 410 * @param trueProbability The estimated probability the condition is true 411 * @return the created {@link IfNode}. 412 */ 413 public IfNode startIf(LogicNode condition, double trueProbability) { 414 AbstractBeginNode thenSuccessor = graph.add(new BeginNode()); 415 AbstractBeginNode elseSuccessor = graph.add(new BeginNode()); 416 IfNode node = append(new IfNode(condition, thenSuccessor, elseSuccessor, trueProbability)); 417 lastFixedNode = null; 418 419 IfStructure s = new IfStructure(); 420 s.state = IfState.CONDITION; 421 s.thenPart = thenSuccessor; 422 s.elsePart = elseSuccessor; 423 pushStructure(s); 424 return node; 425 } 426 427 private IfStructure saveLastIfNode() { 428 IfStructure s = getTopStructure(IfStructure.class); 429 switch (s.state) { 430 case CONDITION: 431 assert lastFixedNode == null; 432 break; 433 case THEN_PART: 434 s.thenPart = lastFixedNode; 435 break; 436 case ELSE_PART: 437 s.elsePart = lastFixedNode; 438 break; 439 case FINISHED: 440 assert false; 441 break; 442 } 443 lastFixedNode = null; 444 return s; 445 } 446 447 public void thenPart() { 448 IfStructure s = saveLastIfNode(); 449 lastFixedNode = (FixedWithNextNode) s.thenPart; 450 s.state = IfState.THEN_PART; 451 } 452 453 public void elsePart() { 454 IfStructure s = saveLastIfNode(); 455 lastFixedNode = (FixedWithNextNode) s.elsePart; 456 s.state = IfState.ELSE_PART; 457 } 458 459 /** 460 * Ends an if block started with {@link #startIf(LogicNode, double)}. 461 * 462 * @return the created merge node, or {@code null} if no merge node was required (for example, 463 * when one part ended with a control sink). 464 */ 465 public AbstractMergeNode endIf() { 466 IfStructure s = saveLastIfNode(); 467 468 FixedWithNextNode thenPart = s.thenPart instanceof FixedWithNextNode ? (FixedWithNextNode) s.thenPart : null; 469 FixedWithNextNode elsePart = s.elsePart instanceof FixedWithNextNode ? (FixedWithNextNode) s.elsePart : null; 470 AbstractMergeNode merge = null; 471 472 if (thenPart != null && elsePart != null) { 473 /* Both parts are alive, we need a real merge. */ 474 EndNode thenEnd = graph.add(new EndNode()); 475 graph.addAfterFixed(thenPart, thenEnd); 476 EndNode elseEnd = graph.add(new EndNode()); 477 graph.addAfterFixed(elsePart, elseEnd); 478 479 merge = graph.add(new MergeNode()); 480 merge.addForwardEnd(thenEnd); 481 merge.addForwardEnd(elseEnd); 482 483 lastFixedNode = merge; 484 485 } else if (thenPart != null) { 486 /* elsePart ended with a control sink, so we can continue with thenPart. */ 487 lastFixedNode = thenPart; 488 489 } else if (elsePart != null) { 490 /* thenPart ended with a control sink, so we can continue with elsePart. */ 491 lastFixedNode = elsePart; 492 493 } else { 494 /* Both parts ended with a control sink, so no nodes can be added after the if. */ 495 assert lastFixedNode == null; 496 } 497 s.state = IfState.FINISHED; 498 popStructure(); 499 return merge; 500 } 501 502 static class InvokeWithExceptionStructure extends Structure { 503 protected enum State { 504 INVOKE, 505 NO_EXCEPTION_EDGE, 506 EXCEPTION_EDGE, 507 FINISHED 508 } 509 510 protected State state; 511 protected ExceptionObjectNode exceptionObject; 512 protected FixedNode noExceptionEdge; 513 protected FixedNode exceptionEdge; 514 } 515 516 public InvokeWithExceptionNode startInvokeWithException(ResolvedJavaMethod method, InvokeKind invokeKind, 517 FrameStateBuilder frameStateBuilder, int invokeBci, int exceptionEdgeBci, ValueNode... args) { 518 519 assert method.isStatic() == (invokeKind == InvokeKind.Static); 520 Signature signature = method.getSignature(); 521 JavaType returnType = signature.getReturnType(null); 522 assert checkArgs(method, args); 523 StampPair returnStamp = graphBuilderPlugins.getOverridingStamp(this, returnType, false); 524 if (returnStamp == null) { 525 returnStamp = StampFactory.forDeclaredType(graph.getAssumptions(), returnType, false); 526 } 527 MethodCallTargetNode callTarget = graph.add(createMethodCallTarget(invokeKind, method, args, returnStamp, invokeBci)); 528 return startInvokeWithException(callTarget, frameStateBuilder, invokeBci, exceptionEdgeBci); 529 } 530 531 public InvokeWithExceptionNode startInvokeWithException(MethodCallTargetNode callTarget, FrameStateBuilder frameStateBuilder, int invokeBci, int exceptionEdgeBci) { 532 ExceptionObjectNode exceptionObject = add(new ExceptionObjectNode(getMetaAccess())); 533 if (frameStateBuilder != null) { 534 FrameStateBuilder exceptionState = frameStateBuilder.copy(); 535 exceptionState.clearStack(); 536 exceptionState.push(JavaKind.Object, exceptionObject); 537 exceptionState.setRethrowException(false); 538 exceptionObject.setStateAfter(exceptionState.create(exceptionEdgeBci, exceptionObject)); 539 } 540 InvokeWithExceptionNode invoke = append(new InvokeWithExceptionNode(callTarget, exceptionObject, invokeBci)); 541 AbstractBeginNode noExceptionEdge = graph.add(KillingBeginNode.create(LocationIdentity.any())); 542 invoke.setNext(noExceptionEdge); 543 if (frameStateBuilder != null) { 544 if (invoke.getStackKind() != JavaKind.Void) { 545 frameStateBuilder.push(invoke.getStackKind(), invoke); 546 } 547 invoke.setStateAfter(frameStateBuilder.create(invokeBci, invoke)); 548 if (invoke.getStackKind() != JavaKind.Void) { 549 frameStateBuilder.pop(invoke.getStackKind()); 550 } 551 } 552 lastFixedNode = null; 553 554 InvokeWithExceptionStructure s = new InvokeWithExceptionStructure(); 555 s.state = InvokeWithExceptionStructure.State.INVOKE; 556 s.noExceptionEdge = noExceptionEdge; 557 s.exceptionEdge = exceptionObject; 558 s.exceptionObject = exceptionObject; 559 pushStructure(s); 560 561 return invoke; 562 } 563 564 private InvokeWithExceptionStructure saveLastInvokeWithExceptionNode() { 565 InvokeWithExceptionStructure s = getTopStructure(InvokeWithExceptionStructure.class); 566 switch (s.state) { 567 case INVOKE: 568 assert lastFixedNode == null; 569 break; 570 case NO_EXCEPTION_EDGE: 571 s.noExceptionEdge = lastFixedNode; 572 break; 573 case EXCEPTION_EDGE: 574 s.exceptionEdge = lastFixedNode; 575 break; 576 case FINISHED: 577 assert false; 578 break; 579 } 580 lastFixedNode = null; 581 return s; 582 } 583 584 public void noExceptionPart() { 585 InvokeWithExceptionStructure s = saveLastInvokeWithExceptionNode(); 586 lastFixedNode = (FixedWithNextNode) s.noExceptionEdge; 587 s.state = InvokeWithExceptionStructure.State.NO_EXCEPTION_EDGE; 588 } 589 590 public void exceptionPart() { 591 InvokeWithExceptionStructure s = saveLastInvokeWithExceptionNode(); 592 lastFixedNode = (FixedWithNextNode) s.exceptionEdge; 593 s.state = InvokeWithExceptionStructure.State.EXCEPTION_EDGE; 594 } 595 596 public ExceptionObjectNode exceptionObject() { 597 InvokeWithExceptionStructure s = getTopStructure(InvokeWithExceptionStructure.class); 598 return s.exceptionObject; 599 } 600 601 /** 602 * Finishes a control flow started with {@link #startInvokeWithException}. If necessary, creates 603 * a merge of the non-exception and exception edges. The merge node is returned and the 604 * non-exception edge is the first forward end of the merge, the exception edge is the second 605 * forward end (relevant for phi nodes). 606 */ 607 public AbstractMergeNode endInvokeWithException() { 608 InvokeWithExceptionStructure s = saveLastInvokeWithExceptionNode(); 609 FixedWithNextNode noExceptionEdge = s.noExceptionEdge instanceof FixedWithNextNode ? (FixedWithNextNode) s.noExceptionEdge : null; 610 FixedWithNextNode exceptionEdge = s.exceptionEdge instanceof FixedWithNextNode ? (FixedWithNextNode) s.exceptionEdge : null; 611 AbstractMergeNode merge = null; 612 if (noExceptionEdge != null && exceptionEdge != null) { 613 EndNode noExceptionEnd = graph.add(new EndNode()); 614 graph.addAfterFixed(noExceptionEdge, noExceptionEnd); 615 EndNode exceptionEnd = graph.add(new EndNode()); 616 graph.addAfterFixed(exceptionEdge, exceptionEnd); 617 merge = graph.add(new MergeNode()); 618 merge.addForwardEnd(noExceptionEnd); 619 merge.addForwardEnd(exceptionEnd); 620 lastFixedNode = merge; 621 } else if (noExceptionEdge != null) { 622 lastFixedNode = noExceptionEdge; 623 } else if (exceptionEdge != null) { 624 lastFixedNode = exceptionEdge; 625 } else { 626 assert lastFixedNode == null; 627 } 628 s.state = InvokeWithExceptionStructure.State.FINISHED; 629 popStructure(); 630 return merge; 631 } 632 }