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