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