1 /* 2 * Copyright (c) 2009, 2015, 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 package org.graalvm.compiler.nodes; 24 25 import static org.graalvm.compiler.nodeinfo.InputType.Association; 26 import static org.graalvm.compiler.nodeinfo.InputType.State; 27 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0; 28 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1; 29 import static jdk.vm.ci.code.BytecodeFrame.getPlaceholderBciName; 30 import static jdk.vm.ci.code.BytecodeFrame.isPlaceholderBci; 31 32 import java.util.ArrayList; 33 import java.util.Collections; 34 import java.util.List; 35 import java.util.Map; 36 import java.util.Objects; 37 38 import org.graalvm.compiler.api.replacements.MethodSubstitution; 39 import org.graalvm.compiler.bytecode.Bytecode; 40 import org.graalvm.compiler.bytecode.Bytecodes; 41 import org.graalvm.compiler.core.common.type.StampFactory; 42 import org.graalvm.compiler.debug.Debug; 43 import org.graalvm.compiler.debug.DebugCounter; 44 import org.graalvm.compiler.debug.GraalError; 45 import org.graalvm.compiler.graph.IterableNodeType; 46 import org.graalvm.compiler.graph.NodeClass; 47 import org.graalvm.compiler.graph.NodeInputList; 48 import org.graalvm.compiler.graph.NodeSourcePosition; 49 import org.graalvm.compiler.graph.iterators.NodeIterable; 50 import org.graalvm.compiler.nodeinfo.InputType; 51 import org.graalvm.compiler.nodeinfo.NodeInfo; 52 import org.graalvm.compiler.nodeinfo.Verbosity; 53 import org.graalvm.compiler.nodes.java.MonitorIdNode; 54 import org.graalvm.compiler.nodes.virtual.EscapeObjectState; 55 import org.graalvm.compiler.nodes.virtual.VirtualObjectNode; 56 57 import jdk.vm.ci.code.BytecodeFrame; 58 import jdk.vm.ci.code.CodeUtil; 59 import jdk.vm.ci.meta.JavaKind; 60 import jdk.vm.ci.meta.ResolvedJavaMethod; 61 62 /** 63 * The {@code FrameState} class encapsulates the frame state (i.e. local variables and operand 64 * stack) at a particular point in the abstract interpretation. 65 * 66 * This can be used as debug or deoptimization information. 67 */ 68 @NodeInfo(nameTemplate = "@{p#code/s}:{p#bci}", cycles = CYCLES_0, size = SIZE_1) 69 public final class FrameState extends VirtualState implements IterableNodeType { 70 public static final NodeClass<FrameState> TYPE = NodeClass.create(FrameState.class); 71 72 private static final DebugCounter FRAMESTATES_COUNTER = Debug.counter("FrameStateCount"); 73 74 /** 75 * Marker value for the second slot of values that occupy two local variable or expression stack 76 * slots. The marker value is used by the bytecode parser, but replaced with {@code null} in the 77 * {@link #values} of the {@link FrameState}. 78 */ 79 public static final ValueNode TWO_SLOT_MARKER = new TwoSlotMarker(); 80 81 @NodeInfo 82 private static final class TwoSlotMarker extends ValueNode { 83 public static final NodeClass<TwoSlotMarker> TYPE = NodeClass.create(TwoSlotMarker.class); 84 85 protected TwoSlotMarker() { 86 super(TYPE, StampFactory.forKind(JavaKind.Illegal)); 87 } 88 } 89 90 protected final int localsSize; 91 92 protected final int stackSize; 93 94 /** 95 * @see BytecodeFrame#rethrowException 96 */ 97 protected boolean rethrowException; 98 99 protected final boolean duringCall; 100 101 @OptionalInput(value = InputType.State) FrameState outerFrameState; 102 103 /** 104 * Contains the locals, the expressions and the locked objects, in this order. 105 */ 106 @OptionalInput NodeInputList<ValueNode> values; 107 108 @OptionalInput(Association) NodeInputList<MonitorIdNode> monitorIds; 109 110 @OptionalInput(State) NodeInputList<EscapeObjectState> virtualObjectMappings; 111 112 /** 113 * The bytecode index to which this frame state applies. 114 */ 115 public final int bci; 116 117 /** 118 * The bytecode to which this frame state applies. 119 */ 120 protected final Bytecode code; 121 122 public FrameState(FrameState outerFrameState, Bytecode code, int bci, int localsSize, int stackSize, int lockSize, boolean rethrowException, boolean duringCall, 123 List<MonitorIdNode> monitorIds, List<EscapeObjectState> virtualObjectMappings) { 124 super(TYPE); 125 if (code != null) { 126 /* 127 * Make sure the bci is within range of the bytecodes. If the code size is 0 then allow 128 * any value, otherwise the bci must be less than the code size. Any negative value is 129 * also allowed to represent special bytecode states. 130 */ 131 int codeSize = code.getCodeSize(); 132 if (codeSize != 0 && bci >= codeSize) { 133 throw new GraalError("bci %d is out of range for %s %d bytes", bci, code.getMethod().format("%H.%n(%p)"), codeSize); 134 } 135 } 136 assert stackSize >= 0; 137 this.outerFrameState = outerFrameState; 138 this.code = code; 139 this.bci = bci; 140 this.localsSize = localsSize; 141 this.stackSize = stackSize; 142 this.values = new NodeInputList<>(this, localsSize + stackSize + lockSize); 143 144 if (monitorIds != null && monitorIds.size() > 0) { 145 this.monitorIds = new NodeInputList<>(this, monitorIds); 146 } 147 148 if (virtualObjectMappings != null && virtualObjectMappings.size() > 0) { 149 this.virtualObjectMappings = new NodeInputList<>(this, virtualObjectMappings); 150 } 151 152 this.rethrowException = rethrowException; 153 this.duringCall = duringCall; 154 assert !this.rethrowException || this.stackSize == 1 : "must have exception on top of the stack"; 155 assert this.locksSize() == this.monitorIdCount(); 156 FRAMESTATES_COUNTER.increment(); 157 } 158 159 public FrameState(FrameState outerFrameState, Bytecode code, int bci, List<ValueNode> values, int localsSize, int stackSize, boolean rethrowException, boolean duringCall, 160 List<MonitorIdNode> monitorIds, List<EscapeObjectState> virtualObjectMappings) { 161 this(outerFrameState, code, bci, localsSize, stackSize, values.size() - localsSize - stackSize, rethrowException, duringCall, monitorIds, virtualObjectMappings); 162 for (int i = 0; i < values.size(); ++i) { 163 this.values.initialize(i, values.get(i)); 164 } 165 } 166 167 private void verifyAfterExceptionState() { 168 if (this.bci == BytecodeFrame.AFTER_EXCEPTION_BCI) { 169 assert this.outerFrameState == null; 170 for (int i = 0; i < this.localsSize; i++) { 171 assertTrue(this.values.get(i) == null, "locals should be null in AFTER_EXCEPTION_BCI state"); 172 } 173 } 174 } 175 176 public FrameState(int bci) { 177 this(null, null, bci, 0, 0, 0, false, false, null, Collections.<EscapeObjectState> emptyList()); 178 assert bci == BytecodeFrame.BEFORE_BCI || bci == BytecodeFrame.AFTER_BCI || bci == BytecodeFrame.AFTER_EXCEPTION_BCI || bci == BytecodeFrame.UNKNOWN_BCI || 179 bci == BytecodeFrame.INVALID_FRAMESTATE_BCI; 180 } 181 182 /** 183 * Creates a placeholder frame state with a single element on the stack representing a return 184 * value. This allows the parsing of an intrinsic to communicate the returned value in a 185 * {@link StateSplit#stateAfter() stateAfter} to the inlining call site. 186 * 187 * @param bci this must be {@link BytecodeFrame#AFTER_BCI} 188 */ 189 public FrameState(int bci, ValueNode returnValue) { 190 this(null, null, bci, 0, returnValue.getStackKind().getSlotCount(), 0, false, false, null, Collections.<EscapeObjectState> emptyList()); 191 assert bci == BytecodeFrame.AFTER_BCI; 192 this.values.initialize(0, returnValue); 193 } 194 195 public FrameState(FrameState outerFrameState, Bytecode code, int bci, ValueNode[] locals, ValueNode[] stack, int stackSize, ValueNode[] locks, List<MonitorIdNode> monitorIds, 196 boolean rethrowException, boolean duringCall) { 197 this(outerFrameState, code, bci, locals.length, stackSize, locks.length, rethrowException, duringCall, monitorIds, Collections.<EscapeObjectState> emptyList()); 198 createValues(locals, stack, locks); 199 } 200 201 private void createValues(ValueNode[] locals, ValueNode[] stack, ValueNode[] locks) { 202 int index = 0; 203 for (int i = 0; i < locals.length; ++i) { 204 ValueNode value = locals[i]; 205 if (value == TWO_SLOT_MARKER) { 206 value = null; 207 } 208 this.values.initialize(index++, value); 209 } 210 for (int i = 0; i < stackSize; ++i) { 211 ValueNode value = stack[i]; 212 if (value == TWO_SLOT_MARKER) { 213 value = null; 214 } 215 this.values.initialize(index++, value); 216 } 217 for (int i = 0; i < locks.length; ++i) { 218 ValueNode value = locks[i]; 219 assert value != TWO_SLOT_MARKER; 220 this.values.initialize(index++, value); 221 } 222 } 223 224 public NodeInputList<ValueNode> values() { 225 return values; 226 } 227 228 public NodeInputList<MonitorIdNode> monitorIds() { 229 return monitorIds; 230 } 231 232 public FrameState outerFrameState() { 233 return outerFrameState; 234 } 235 236 public void setOuterFrameState(FrameState x) { 237 assert x == null || !x.isDeleted(); 238 updateUsages(this.outerFrameState, x); 239 this.outerFrameState = x; 240 } 241 242 public static NodeSourcePosition toSourcePosition(FrameState fs) { 243 if (fs == null) { 244 return null; 245 } 246 return new NodeSourcePosition(null, toSourcePosition(fs.outerFrameState()), fs.code.getMethod(), fs.bci); 247 } 248 249 /** 250 * @see BytecodeFrame#rethrowException 251 */ 252 public boolean rethrowException() { 253 return rethrowException; 254 } 255 256 public boolean duringCall() { 257 return duringCall; 258 } 259 260 public Bytecode getCode() { 261 return code; 262 } 263 264 public ResolvedJavaMethod getMethod() { 265 return code == null ? null : code.getMethod(); 266 } 267 268 /** 269 * Determines if this frame state can be converted to a {@link BytecodeFrame}. 270 * 271 * Since a {@link BytecodeFrame} encodes {@link #getMethod()} and {@link #bci}, it does not 272 * preserve {@link #getCode()}. {@link #bci} is only guaranteed to be valid in terms of 273 * {@code getCode().getCode()} which may be different from {@code getMethod().getCode()} if the 274 * latter has been subject to instrumentation. 275 */ 276 public boolean canProduceBytecodeFrame() { 277 return code != null && code.getCode() == code.getMethod().getCode(); 278 } 279 280 public void addVirtualObjectMapping(EscapeObjectState virtualObject) { 281 if (virtualObjectMappings == null) { 282 virtualObjectMappings = new NodeInputList<>(this); 283 } 284 virtualObjectMappings.add(virtualObject); 285 } 286 287 public int virtualObjectMappingCount() { 288 if (virtualObjectMappings == null) { 289 return 0; 290 } 291 return virtualObjectMappings.size(); 292 } 293 294 public EscapeObjectState virtualObjectMappingAt(int i) { 295 return virtualObjectMappings.get(i); 296 } 297 298 public NodeInputList<EscapeObjectState> virtualObjectMappings() { 299 return virtualObjectMappings; 300 } 301 302 /** 303 * Gets a copy of this frame state. 304 */ 305 public FrameState duplicate(int newBci) { 306 return graph().add(new FrameState(outerFrameState(), code, newBci, values, localsSize, stackSize, rethrowException, duringCall, monitorIds, virtualObjectMappings)); 307 } 308 309 /** 310 * Gets a copy of this frame state. 311 */ 312 public FrameState duplicate() { 313 return duplicate(bci); 314 } 315 316 /** 317 * Duplicates a FrameState, along with a deep copy of all connected VirtualState (outer 318 * FrameStates, VirtualObjectStates, ...). 319 */ 320 @Override 321 public FrameState duplicateWithVirtualState() { 322 FrameState newOuterFrameState = outerFrameState(); 323 if (newOuterFrameState != null) { 324 newOuterFrameState = newOuterFrameState.duplicateWithVirtualState(); 325 } 326 ArrayList<EscapeObjectState> newVirtualMappings = null; 327 if (virtualObjectMappings != null) { 328 newVirtualMappings = new ArrayList<>(virtualObjectMappings.size()); 329 for (EscapeObjectState state : virtualObjectMappings) { 330 newVirtualMappings.add(state.duplicateWithVirtualState()); 331 } 332 } 333 return graph().add(new FrameState(newOuterFrameState, code, bci, values, localsSize, stackSize, rethrowException, duringCall, monitorIds, newVirtualMappings)); 334 } 335 336 /** 337 * Creates a copy of this frame state with one stack element of type {@code popKind} popped from 338 * the stack. 339 */ 340 public FrameState duplicateModifiedDuringCall(int newBci, JavaKind popKind) { 341 return duplicateModified(graph(), newBci, rethrowException, true, popKind, null, null); 342 } 343 344 public FrameState duplicateModifiedBeforeCall(int newBci, JavaKind popKind, JavaKind[] pushedSlotKinds, ValueNode[] pushedValues) { 345 return duplicateModified(graph(), newBci, rethrowException, false, popKind, pushedSlotKinds, pushedValues); 346 } 347 348 /** 349 * Creates a copy of this frame state with one stack element of type {@code popKind} popped from 350 * the stack and the values in {@code pushedValues} pushed on the stack. The 351 * {@code pushedValues} will be formatted correctly in slot encoding: a long or double will be 352 * followed by a null slot. 353 */ 354 public FrameState duplicateModified(int newBci, boolean newRethrowException, JavaKind popKind, JavaKind[] pushedSlotKinds, ValueNode[] pushedValues) { 355 return duplicateModified(graph(), newBci, newRethrowException, duringCall, popKind, pushedSlotKinds, pushedValues); 356 } 357 358 public FrameState duplicateModified(int newBci, boolean newRethrowException, boolean newDuringCall, JavaKind popKind, JavaKind[] pushedSlotKinds, ValueNode[] pushedValues) { 359 return duplicateModified(graph(), newBci, newRethrowException, newDuringCall, popKind, pushedSlotKinds, pushedValues); 360 } 361 362 /** 363 * Creates a copy of this frame state with the top of stack replaced with with 364 * {@code pushedValue} which must be of type {@code popKind}. 365 */ 366 public FrameState duplicateModified(JavaKind popKind, JavaKind pushedSlotKind, ValueNode pushedValue) { 367 assert pushedValue != null && pushedValue.getStackKind() == popKind; 368 return duplicateModified(graph(), bci, rethrowException, duringCall, popKind, new JavaKind[]{pushedSlotKind}, new ValueNode[]{pushedValue}); 369 } 370 371 /** 372 * Creates a copy of this frame state with one stack element of type popKind popped from the 373 * stack and the values in pushedValues pushed on the stack. The pushedValues will be formatted 374 * correctly in slot encoding: a long or double will be followed by a null slot. The bci will be 375 * changed to newBci. 376 */ 377 public FrameState duplicateModified(StructuredGraph graph, int newBci, boolean newRethrowException, boolean newDuringCall, JavaKind popKind, JavaKind[] pushedSlotKinds, ValueNode[] pushedValues) { 378 ArrayList<ValueNode> copy; 379 if (newRethrowException && !rethrowException && popKind == JavaKind.Void) { 380 assert popKind == JavaKind.Void; 381 copy = new ArrayList<>(values.subList(0, localsSize)); 382 } else { 383 copy = new ArrayList<>(values.subList(0, localsSize + stackSize)); 384 if (popKind != JavaKind.Void) { 385 if (stackAt(stackSize() - 1) == null) { 386 copy.remove(copy.size() - 1); 387 } 388 ValueNode lastSlot = copy.get(copy.size() - 1); 389 assert lastSlot.getStackKind() == popKind.getStackKind(); 390 copy.remove(copy.size() - 1); 391 } 392 } 393 if (pushedValues != null) { 394 assert pushedSlotKinds.length == pushedValues.length; 395 for (int i = 0; i < pushedValues.length; i++) { 396 copy.add(pushedValues[i]); 397 if (pushedSlotKinds[i].needsTwoSlots()) { 398 copy.add(null); 399 } 400 } 401 } 402 int newStackSize = copy.size() - localsSize; 403 copy.addAll(values.subList(localsSize + stackSize, values.size())); 404 405 assert checkStackDepth(bci, stackSize, duringCall, rethrowException, newBci, newStackSize, newDuringCall, newRethrowException); 406 return graph.add(new FrameState(outerFrameState(), code, newBci, copy, localsSize, newStackSize, newRethrowException, newDuringCall, monitorIds, virtualObjectMappings)); 407 } 408 409 /** 410 * Perform a few sanity checks on the transformation of the stack state. The current expectation 411 * is that a stateAfter is being transformed into a stateDuring, so the stack depth may change. 412 */ 413 private boolean checkStackDepth(int oldBci, int oldStackSize, boolean oldDuringCall, boolean oldRethrowException, int newBci, int newStackSize, boolean newDuringCall, 414 boolean newRethrowException) { 415 if (BytecodeFrame.isPlaceholderBci(oldBci)) { 416 return true; 417 } 418 /* 419 * It would be nice to have a complete check of the shape of the FrameState based on a 420 * dataflow of the bytecodes but for now just check for obvious expression stack depth 421 * mistakes. 422 */ 423 byte[] codes = code.getCode(); 424 if (codes == null) { 425 /* Graph was constructed manually. */ 426 return true; 427 } 428 byte newCode = codes[newBci]; 429 if (oldBci == newBci) { 430 assert oldStackSize == newStackSize || oldDuringCall != newDuringCall || oldRethrowException != newRethrowException : "bci is unchanged, stack depth shouldn't change"; 431 } else { 432 byte oldCode = codes[oldBci]; 433 assert Bytecodes.lengthOf(newCode) + newBci == oldBci || Bytecodes.lengthOf(oldCode) + oldBci == newBci : "expecting roll back or forward"; 434 } 435 return true; 436 } 437 438 /** 439 * Gets the size of the local variables. 440 */ 441 public int localsSize() { 442 return localsSize; 443 } 444 445 /** 446 * Gets the current size (height) of the stack. 447 */ 448 public int stackSize() { 449 return stackSize; 450 } 451 452 /** 453 * Gets the number of locked monitors in this frame state. 454 */ 455 public int locksSize() { 456 return values.size() - localsSize - stackSize; 457 } 458 459 /** 460 * Gets the number of locked monitors in this frame state and all {@linkplain #outerFrameState() 461 * outer} frame states. 462 */ 463 public int nestedLockDepth() { 464 int depth = locksSize(); 465 for (FrameState outer = outerFrameState(); outer != null; outer = outer.outerFrameState()) { 466 depth += outer.locksSize(); 467 } 468 return depth; 469 } 470 471 /** 472 * Gets the value in the local variables at the specified index. 473 * 474 * @param i the index into the locals 475 * @return the instruction that produced the value for the specified local 476 */ 477 public ValueNode localAt(int i) { 478 assert i >= 0 && i < localsSize : "local variable index out of range: " + i; 479 return values.get(i); 480 } 481 482 /** 483 * Get the value on the stack at the specified stack index. 484 * 485 * @param i the index into the stack, with {@code 0} being the bottom of the stack 486 * @return the instruction at the specified position in the stack 487 */ 488 public ValueNode stackAt(int i) { 489 assert i >= 0 && i < stackSize; 490 return values.get(localsSize + i); 491 } 492 493 /** 494 * Get the monitor owner at the specified index. 495 * 496 * @param i the index into the list of locked monitors. 497 * @return the lock owner at the given index. 498 */ 499 public ValueNode lockAt(int i) { 500 assert i >= 0 && i < locksSize(); 501 return values.get(localsSize + stackSize + i); 502 } 503 504 /** 505 * Get the MonitorIdNode that corresponds to the locked object at the specified index. 506 */ 507 public MonitorIdNode monitorIdAt(int i) { 508 assert monitorIds != null && i >= 0 && i < locksSize(); 509 return monitorIds.get(i); 510 } 511 512 public int monitorIdCount() { 513 if (monitorIds == null) { 514 return 0; 515 } else { 516 return monitorIds.size(); 517 } 518 } 519 520 public NodeIterable<FrameState> innerFrameStates() { 521 return usages().filter(FrameState.class); 522 } 523 524 private static String toString(FrameState frameState) { 525 StringBuilder sb = new StringBuilder(); 526 String nl = CodeUtil.NEW_LINE; 527 FrameState fs = frameState; 528 while (fs != null) { 529 Bytecode.appendLocation(sb, fs.getCode(), fs.bci); 530 if (BytecodeFrame.isPlaceholderBci(fs.bci)) { 531 sb.append("//").append(getPlaceholderBciName(fs.bci)); 532 } 533 sb.append(nl); 534 sb.append("locals: ["); 535 for (int i = 0; i < fs.localsSize(); i++) { 536 sb.append(i == 0 ? "" : ", ").append(fs.localAt(i) == null ? "_" : fs.localAt(i).toString(Verbosity.Id)); 537 } 538 sb.append("]").append(nl).append("stack: ["); 539 for (int i = 0; i < fs.stackSize(); i++) { 540 sb.append(i == 0 ? "" : ", ").append(fs.stackAt(i) == null ? "_" : fs.stackAt(i).toString(Verbosity.Id)); 541 } 542 sb.append("]").append(nl).append("locks: ["); 543 for (int i = 0; i < fs.locksSize(); i++) { 544 sb.append(i == 0 ? "" : ", ").append(fs.lockAt(i) == null ? "_" : fs.lockAt(i).toString(Verbosity.Id)); 545 } 546 sb.append(']').append(nl); 547 fs = fs.outerFrameState(); 548 } 549 return sb.toString(); 550 } 551 552 @Override 553 public String toString(Verbosity verbosity) { 554 if (verbosity == Verbosity.Debugger) { 555 return toString(this); 556 } else if (verbosity == Verbosity.Name) { 557 String res = super.toString(Verbosity.Name) + "@" + bci; 558 if (BytecodeFrame.isPlaceholderBci(bci)) { 559 res += "[" + getPlaceholderBciName(bci) + "]"; 560 } 561 return res; 562 } else { 563 return super.toString(verbosity); 564 } 565 } 566 567 @Override 568 public Map<Object, Object> getDebugProperties(Map<Object, Object> map) { 569 Map<Object, Object> properties = super.getDebugProperties(map); 570 if (code != null) { 571 // properties.put("method", MetaUtil.format("%H.%n(%p):%r", method)); 572 StackTraceElement ste = code.asStackTraceElement(bci); 573 if (ste.getFileName() != null && ste.getLineNumber() >= 0) { 574 properties.put("sourceFile", ste.getFileName()); 575 properties.put("sourceLine", ste.getLineNumber()); 576 } 577 } 578 if (isPlaceholderBci(bci)) { 579 properties.put("bci", getPlaceholderBciName(bci)); 580 } 581 properties.put("locksSize", values.size() - stackSize - localsSize); 582 return properties; 583 } 584 585 @Override 586 public boolean verify() { 587 if (virtualObjectMappingCount() > 0) { 588 for (EscapeObjectState state : virtualObjectMappings()) { 589 assertTrue(state != null, "must be non-null"); 590 } 591 } 592 /* 593 * The outermost FrameState should have a method that matches StructuredGraph.method except 594 * when it's a substitution or it's null. 595 */ 596 assertTrue(outerFrameState != null || graph() == null || graph().method() == null || code == null || Objects.equals(graph().method(), code.getMethod()) || 597 graph().method().getAnnotation(MethodSubstitution.class) != null, "wrong outerFrameState %s != %s", code == null ? "null" : code.getMethod(), graph().method()); 598 if (monitorIds() != null && monitorIds().size() > 0) { 599 int depth = outerLockDepth(); 600 for (MonitorIdNode monitor : monitorIds()) { 601 assertTrue(monitor.getLockDepth() == depth++, "wrong depth"); 602 } 603 } 604 assertTrue(locksSize() == monitorIdCount(), "mismatch in number of locks"); 605 for (ValueNode value : values) { 606 assertTrue(value == null || !value.isDeleted(), "frame state must not contain deleted nodes: %s", value); 607 assertTrue(value == null || value instanceof VirtualObjectNode || (value.getStackKind() != JavaKind.Void), "unexpected value: %s", value); 608 } 609 verifyAfterExceptionState(); 610 return super.verify(); 611 } 612 613 private int outerLockDepth() { 614 int depth = 0; 615 FrameState outer = outerFrameState; 616 while (outer != null) { 617 depth += outer.monitorIdCount(); 618 outer = outer.outerFrameState; 619 } 620 return depth; 621 } 622 623 @Override 624 public void applyToNonVirtual(NodeClosure<? super ValueNode> closure) { 625 for (ValueNode value : values) { 626 if (value != null) { 627 closure.apply(this, value); 628 } 629 } 630 631 if (monitorIds != null) { 632 for (MonitorIdNode monitorId : monitorIds) { 633 if (monitorId != null) { 634 closure.apply(this, monitorId); 635 } 636 } 637 } 638 639 if (virtualObjectMappings != null) { 640 for (EscapeObjectState state : virtualObjectMappings) { 641 state.applyToNonVirtual(closure); 642 } 643 } 644 645 if (outerFrameState() != null) { 646 outerFrameState().applyToNonVirtual(closure); 647 } 648 } 649 650 @Override 651 public void applyToVirtual(VirtualClosure closure) { 652 closure.apply(this); 653 if (virtualObjectMappings != null) { 654 for (EscapeObjectState state : virtualObjectMappings) { 655 state.applyToVirtual(closure); 656 } 657 } 658 if (outerFrameState() != null) { 659 outerFrameState().applyToVirtual(closure); 660 } 661 } 662 663 @Override 664 public boolean isPartOfThisState(VirtualState state) { 665 if (state == this) { 666 return true; 667 } 668 if (outerFrameState() != null && outerFrameState().isPartOfThisState(state)) { 669 return true; 670 } 671 if (virtualObjectMappings != null) { 672 for (EscapeObjectState objectState : virtualObjectMappings) { 673 if (objectState.isPartOfThisState(state)) { 674 return true; 675 } 676 } 677 } 678 return false; 679 } 680 }