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