1 /* 2 * Copyright (c) 2012, 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.java; 26 27 import static org.graalvm.compiler.bytecode.Bytecodes.DUP; 28 import static org.graalvm.compiler.bytecode.Bytecodes.DUP2; 29 import static org.graalvm.compiler.bytecode.Bytecodes.DUP2_X1; 30 import static org.graalvm.compiler.bytecode.Bytecodes.DUP2_X2; 31 import static org.graalvm.compiler.bytecode.Bytecodes.DUP_X1; 32 import static org.graalvm.compiler.bytecode.Bytecodes.DUP_X2; 33 import static org.graalvm.compiler.bytecode.Bytecodes.POP; 34 import static org.graalvm.compiler.bytecode.Bytecodes.POP2; 35 import static org.graalvm.compiler.bytecode.Bytecodes.SWAP; 36 import static org.graalvm.compiler.debug.GraalError.shouldNotReachHere; 37 import static org.graalvm.compiler.nodes.FrameState.TWO_SLOT_MARKER; 38 39 import java.util.ArrayList; 40 import java.util.Arrays; 41 import java.util.List; 42 import java.util.function.Function; 43 44 import org.graalvm.compiler.bytecode.Bytecode; 45 import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode; 46 import org.graalvm.compiler.core.common.GraalOptions; 47 import org.graalvm.compiler.core.common.PermanentBailoutException; 48 import org.graalvm.compiler.core.common.type.StampFactory; 49 import org.graalvm.compiler.core.common.type.StampPair; 50 import org.graalvm.compiler.debug.DebugContext; 51 import org.graalvm.compiler.debug.GraalError; 52 import org.graalvm.compiler.graph.NodeSourcePosition; 53 import org.graalvm.compiler.java.BciBlockMapping.BciBlock; 54 import org.graalvm.compiler.nodeinfo.Verbosity; 55 import org.graalvm.compiler.nodes.AbstractMergeNode; 56 import org.graalvm.compiler.nodes.ConstantNode; 57 import org.graalvm.compiler.nodes.FrameState; 58 import org.graalvm.compiler.nodes.LoopBeginNode; 59 import org.graalvm.compiler.nodes.LoopExitNode; 60 import org.graalvm.compiler.nodes.NodeView; 61 import org.graalvm.compiler.nodes.ParameterNode; 62 import org.graalvm.compiler.nodes.PhiNode; 63 import org.graalvm.compiler.nodes.ProxyNode; 64 import org.graalvm.compiler.nodes.StateSplit; 65 import org.graalvm.compiler.nodes.StructuredGraph; 66 import org.graalvm.compiler.nodes.ValueNode; 67 import org.graalvm.compiler.nodes.ValuePhiNode; 68 import org.graalvm.compiler.nodes.calc.FloatingNode; 69 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; 70 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderTool; 71 import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.SideEffectsState; 72 import org.graalvm.compiler.nodes.graphbuilderconf.ParameterPlugin; 73 import org.graalvm.compiler.nodes.java.MonitorIdNode; 74 import org.graalvm.compiler.nodes.util.GraphUtil; 75 76 import jdk.vm.ci.code.BytecodeFrame; 77 import jdk.vm.ci.meta.Assumptions; 78 import jdk.vm.ci.meta.JavaKind; 79 import jdk.vm.ci.meta.JavaType; 80 import jdk.vm.ci.meta.ResolvedJavaMethod; 81 import jdk.vm.ci.meta.ResolvedJavaType; 82 import jdk.vm.ci.meta.Signature; 83 84 public final class FrameStateBuilder implements SideEffectsState { 85 86 private static final ValueNode[] EMPTY_ARRAY = new ValueNode[0]; 87 private static final MonitorIdNode[] EMPTY_MONITOR_ARRAY = new MonitorIdNode[0]; 88 89 private final BytecodeParser parser; 90 private final GraphBuilderTool tool; 91 private final Bytecode code; 92 private int stackSize; 93 protected final ValueNode[] locals; 94 protected final ValueNode[] stack; 95 private ValueNode[] lockedObjects; 96 private boolean canVerifyKind; 97 98 /** 99 * @see BytecodeFrame#rethrowException 100 */ 101 private boolean rethrowException; 102 103 private MonitorIdNode[] monitorIds; 104 private final StructuredGraph graph; 105 private final boolean clearNonLiveLocals; 106 private FrameState outerFrameState; 107 private NodeSourcePosition outerSourcePosition; 108 109 /** 110 * The closest {@link StateSplit#hasSideEffect() side-effect} predecessors. There will be more 111 * than one when the current block contains no side-effects but merging predecessor blocks do. 112 */ 113 private List<StateSplit> sideEffects; 114 115 /** 116 * Creates a new frame state builder for the given method and the given target graph. 117 * 118 * @param method the method whose frame is simulated 119 * @param graph the target graph of Graal nodes created by the builder 120 */ 121 public FrameStateBuilder(GraphBuilderTool tool, ResolvedJavaMethod method, StructuredGraph graph) { 122 this(tool, new ResolvedJavaMethodBytecode(method), graph, false); 123 } 124 125 /** 126 * Creates a new frame state builder for the given code attribute, method and the given target 127 * graph. Additionally specifies if nonLiveLocals should be retained. 128 * 129 * @param code the bytecode in which the frame exists 130 * @param graph the target graph of Graal nodes created by the builder 131 * @param shouldRetainLocalVariables specifies if nonLiveLocals should be retained in state. 132 */ 133 public FrameStateBuilder(GraphBuilderTool tool, Bytecode code, StructuredGraph graph, boolean shouldRetainLocalVariables) { 134 this.tool = tool; 135 if (tool instanceof BytecodeParser) { 136 this.parser = (BytecodeParser) tool; 137 } else { 138 this.parser = null; 139 } 140 this.code = code; 141 this.locals = allocateArray(code.getMaxLocals()); 142 this.stack = allocateArray(Math.max(1, code.getMaxStackSize())); 143 this.lockedObjects = allocateArray(0); 144 145 assert graph != null; 146 147 this.monitorIds = EMPTY_MONITOR_ARRAY; 148 this.graph = graph; 149 this.clearNonLiveLocals = GraalOptions.OptClearNonLiveLocals.getValue(graph.getOptions()) && !shouldRetainLocalVariables; 150 this.canVerifyKind = true; 151 } 152 153 public void disableKindVerification() { 154 canVerifyKind = false; 155 } 156 157 public void initializeFromArgumentsArray(ValueNode[] arguments) { 158 159 int javaIndex = 0; 160 int index = 0; 161 if (!getMethod().isStatic()) { 162 // set the receiver 163 locals[javaIndex] = arguments[index]; 164 javaIndex = 1; 165 index = 1; 166 } 167 Signature sig = getMethod().getSignature(); 168 int max = sig.getParameterCount(false); 169 for (int i = 0; i < max; i++) { 170 JavaKind kind = sig.getParameterKind(i); 171 locals[javaIndex] = arguments[index]; 172 javaIndex++; 173 if (kind.needsTwoSlots()) { 174 locals[javaIndex] = TWO_SLOT_MARKER; 175 javaIndex++; 176 } 177 index++; 178 } 179 } 180 181 public void initializeForMethodStart(Assumptions assumptions, boolean eagerResolve, Plugins plugins) { 182 183 int javaIndex = 0; 184 int index = 0; 185 ResolvedJavaMethod method = getMethod(); 186 ResolvedJavaType originalType = method.getDeclaringClass(); 187 if (!method.isStatic()) { 188 // add the receiver 189 FloatingNode receiver = null; 190 StampPair receiverStamp = null; 191 if (plugins != null) { 192 receiverStamp = plugins.getOverridingStamp(tool, originalType, true); 193 } 194 if (receiverStamp == null) { 195 receiverStamp = StampFactory.forDeclaredType(assumptions, originalType, true); 196 } 197 198 if (plugins != null) { 199 for (ParameterPlugin plugin : plugins.getParameterPlugins()) { 200 receiver = plugin.interceptParameter(tool, index, receiverStamp); 201 if (receiver != null) { 202 break; 203 } 204 } 205 } 206 if (receiver == null) { 207 receiver = new ParameterNode(javaIndex, receiverStamp); 208 } 209 210 locals[javaIndex] = graph.addOrUniqueWithInputs(receiver); 211 javaIndex = 1; 212 index = 1; 213 } 214 Signature sig = method.getSignature(); 215 int max = sig.getParameterCount(false); 216 ResolvedJavaType accessingClass = originalType; 217 for (int i = 0; i < max; i++) { 218 JavaType type = sig.getParameterType(i, accessingClass); 219 if (eagerResolve) { 220 type = type.resolve(accessingClass); 221 } 222 JavaKind kind = type.getJavaKind(); 223 StampPair stamp = null; 224 if (plugins != null) { 225 stamp = plugins.getOverridingStamp(tool, type, false); 226 } 227 if (stamp == null) { 228 // GR-714: subword inputs cannot be trusted 229 if (kind.getStackKind() != kind) { 230 stamp = StampPair.createSingle(StampFactory.forKind(JavaKind.Int)); 231 } else { 232 stamp = StampFactory.forDeclaredType(assumptions, type, false); 233 } 234 } 235 236 FloatingNode param = null; 237 if (plugins != null) { 238 for (ParameterPlugin plugin : plugins.getParameterPlugins()) { 239 param = plugin.interceptParameter(tool, index, stamp); 240 if (param != null) { 241 break; 242 } 243 } 244 } 245 if (param == null) { 246 param = new ParameterNode(index, stamp); 247 } 248 249 locals[javaIndex] = graph.addOrUniqueWithInputs(param); 250 javaIndex++; 251 if (kind.needsTwoSlots()) { 252 locals[javaIndex] = TWO_SLOT_MARKER; 253 javaIndex++; 254 } 255 index++; 256 } 257 } 258 259 private FrameStateBuilder(FrameStateBuilder other) { 260 this.parser = other.parser; 261 this.tool = other.tool; 262 this.code = other.code; 263 this.stackSize = other.stackSize; 264 this.locals = other.locals.clone(); 265 this.stack = other.stack.clone(); 266 this.lockedObjects = other.lockedObjects.length == 0 ? other.lockedObjects : other.lockedObjects.clone(); 267 this.rethrowException = other.rethrowException; 268 this.canVerifyKind = other.canVerifyKind; 269 270 assert locals.length == code.getMaxLocals(); 271 assert stack.length == Math.max(1, code.getMaxStackSize()); 272 273 assert other.graph != null; 274 graph = other.graph; 275 clearNonLiveLocals = other.clearNonLiveLocals; 276 monitorIds = other.monitorIds.length == 0 ? other.monitorIds : other.monitorIds.clone(); 277 278 assert locals.length == code.getMaxLocals(); 279 assert stack.length == Math.max(1, code.getMaxStackSize()); 280 assert lockedObjects.length == monitorIds.length; 281 } 282 283 private static ValueNode[] allocateArray(int length) { 284 return length == 0 ? EMPTY_ARRAY : new ValueNode[length]; 285 } 286 287 public ResolvedJavaMethod getMethod() { 288 return code.getMethod(); 289 } 290 291 @Override 292 public String toString() { 293 StringBuilder sb = new StringBuilder(); 294 sb.append("[locals: ["); 295 for (int i = 0; i < locals.length; i++) { 296 sb.append(i == 0 ? "" : ",").append(locals[i] == null ? "_" : locals[i] == TWO_SLOT_MARKER ? "#" : locals[i].toString(Verbosity.Id)); 297 } 298 sb.append("] stack: ["); 299 for (int i = 0; i < stackSize; i++) { 300 sb.append(i == 0 ? "" : ",").append(stack[i] == null ? "_" : stack[i] == TWO_SLOT_MARKER ? "#" : stack[i].toString(Verbosity.Id)); 301 } 302 sb.append("] locks: ["); 303 for (int i = 0; i < lockedObjects.length; i++) { 304 sb.append(i == 0 ? "" : ",").append(lockedObjects[i].toString(Verbosity.Id)).append(" / ").append(monitorIds[i].toString(Verbosity.Id)); 305 } 306 sb.append("]"); 307 if (rethrowException) { 308 sb.append(" rethrowException"); 309 } 310 sb.append("]"); 311 return sb.toString(); 312 } 313 314 public FrameState create(int bci, StateSplit forStateSplit) { 315 if (parser != null && parser.parsingIntrinsic()) { 316 NodeSourcePosition sourcePosition = parser.getGraph().trackNodeSourcePosition() ? createBytecodePosition(bci) : null; 317 return parser.intrinsicContext.createFrameState(parser.getGraph(), this, forStateSplit, sourcePosition); 318 } 319 320 // Skip intrinsic frames 321 return create(bci, parser != null ? parser.getNonIntrinsicAncestor() : null, false, null, null); 322 } 323 324 /** 325 * @param pushedValues if non-null, values to {@link #push(JavaKind, ValueNode)} to the stack 326 * before creating the {@link FrameState} 327 */ 328 public FrameState create(int bci, BytecodeParser parent, boolean duringCall, JavaKind[] pushedSlotKinds, ValueNode[] pushedValues) { 329 if (outerFrameState == null && parent != null) { 330 assert !parent.parsingIntrinsic() : "must already have the next non-intrinsic ancestor"; 331 outerFrameState = parent.getFrameStateBuilder().create(parent.bci(), parent.getNonIntrinsicAncestor(), true, null, null); 332 } 333 if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI && parent != null) { 334 FrameState newFrameState = outerFrameState.duplicateModified(outerFrameState.bci, true, false, JavaKind.Void, new JavaKind[]{JavaKind.Object}, new ValueNode[]{stack[0]}); 335 return newFrameState; 336 } 337 if (bci == BytecodeFrame.INVALID_FRAMESTATE_BCI) { 338 throw shouldNotReachHere(); 339 } 340 341 if (pushedValues != null) { 342 assert pushedSlotKinds.length == pushedValues.length; 343 int stackSizeToRestore = stackSize; 344 for (int i = 0; i < pushedValues.length; i++) { 345 push(pushedSlotKinds[i], pushedValues[i]); 346 } 347 FrameState res = graph.add(new FrameState(outerFrameState, code, bci, locals, stack, stackSize, lockedObjects, Arrays.asList(monitorIds), rethrowException, duringCall)); 348 stackSize = stackSizeToRestore; 349 return res; 350 } else { 351 if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI) { 352 assert outerFrameState == null; 353 clearLocals(); 354 } 355 return graph.add(new FrameState(outerFrameState, code, bci, locals, stack, stackSize, lockedObjects, Arrays.asList(monitorIds), rethrowException, duringCall)); 356 } 357 } 358 359 public NodeSourcePosition createBytecodePosition(int bci) { 360 BytecodeParser parent = parser.getParent(); 361 NodeSourcePosition position = create(bci, parent); 362 return position; 363 } 364 365 private NodeSourcePosition create(int bci, BytecodeParser parent) { 366 if (outerSourcePosition == null && parent != null) { 367 outerSourcePosition = parent.getFrameStateBuilder().createBytecodePosition(parent.bci()); 368 } 369 if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI && parent != null) { 370 return FrameState.toSourcePosition(outerFrameState); 371 } 372 if (bci == BytecodeFrame.INVALID_FRAMESTATE_BCI) { 373 throw shouldNotReachHere(); 374 } 375 if (parser.intrinsicContext != null && (parent == null || parent.intrinsicContext != parser.intrinsicContext)) { 376 // When parsing an intrinsic put in a substitution marker showing the original method as 377 // the caller. This keeps the relationship between the method and the method 378 // substitution clear in resulting NodeSourcePosition. 379 NodeSourcePosition original = new NodeSourcePosition(outerSourcePosition, parser.intrinsicContext.getOriginalMethod(), -1); 380 return NodeSourcePosition.substitution(original, code.getMethod(), bci); 381 } else { 382 return new NodeSourcePosition(outerSourcePosition, code.getMethod(), bci); 383 } 384 } 385 386 public FrameStateBuilder copy() { 387 return new FrameStateBuilder(this); 388 } 389 390 public boolean isCompatibleWith(FrameStateBuilder other) { 391 assert code.equals(other.code) && graph == other.graph && localsSize() == other.localsSize() : "Can only compare frame states of the same method"; 392 assert lockedObjects.length == monitorIds.length && other.lockedObjects.length == other.monitorIds.length : "mismatch between lockedObjects and monitorIds"; 393 394 if (rethrowException != other.rethrowException) { 395 return false; 396 } 397 398 if (stackSize() != other.stackSize()) { 399 return false; 400 } 401 for (int i = 0; i < stackSize(); i++) { 402 ValueNode x = stack[i]; 403 ValueNode y = other.stack[i]; 404 assert x != null && y != null; 405 if (x != y && (x == TWO_SLOT_MARKER || x.isDeleted() || y == TWO_SLOT_MARKER || y.isDeleted() || x.getStackKind() != y.getStackKind())) { 406 return false; 407 } 408 } 409 if (lockedObjects.length != other.lockedObjects.length) { 410 return false; 411 } 412 for (int i = 0; i < lockedObjects.length; i++) { 413 if (GraphUtil.originalValue(lockedObjects[i]) != GraphUtil.originalValue(other.lockedObjects[i]) || monitorIds[i] != other.monitorIds[i]) { 414 throw new PermanentBailoutException("unbalanced monitors"); 415 } 416 } 417 return true; 418 } 419 420 public void merge(AbstractMergeNode block, FrameStateBuilder other) { 421 GraalError.guarantee(isCompatibleWith(other), "stacks do not match on merge; bytecodes would not verify:%nexpect: %s%nactual: %s", block, other); 422 423 for (int i = 0; i < localsSize(); i++) { 424 locals[i] = merge(locals[i], other.locals[i], block); 425 } 426 for (int i = 0; i < stackSize(); i++) { 427 stack[i] = merge(stack[i], other.stack[i], block); 428 } 429 for (int i = 0; i < lockedObjects.length; i++) { 430 lockedObjects[i] = merge(lockedObjects[i], other.lockedObjects[i], block); 431 assert monitorIds[i] == other.monitorIds[i]; 432 } 433 434 if (sideEffects == null) { 435 sideEffects = other.sideEffects; 436 } else { 437 if (other.sideEffects != null) { 438 sideEffects.addAll(other.sideEffects); 439 } 440 } 441 } 442 443 private ValueNode merge(ValueNode currentValue, ValueNode otherValue, AbstractMergeNode block) { 444 if (currentValue == null || currentValue.isDeleted()) { 445 return null; 446 } else if (block.isPhiAtMerge(currentValue)) { 447 if (otherValue == null || otherValue == TWO_SLOT_MARKER || otherValue.isDeleted() || currentValue.getStackKind() != otherValue.getStackKind()) { 448 // This phi must be dead anyway, add input of correct stack kind to keep the graph 449 // invariants. 450 ((PhiNode) currentValue).addInput(ConstantNode.defaultForKind(currentValue.getStackKind(), graph)); 451 } else { 452 ((PhiNode) currentValue).addInput(otherValue); 453 } 454 return currentValue; 455 } else if (currentValue != otherValue) { 456 if (currentValue == TWO_SLOT_MARKER || otherValue == TWO_SLOT_MARKER) { 457 return null; 458 } else if (otherValue == null || otherValue.isDeleted() || currentValue.getStackKind() != otherValue.getStackKind()) { 459 return null; 460 } 461 assert !(block instanceof LoopBeginNode) : String.format("Phi functions for loop headers are create eagerly for changed locals and all stack slots: %s != %s", currentValue, otherValue); 462 return createValuePhi(currentValue, otherValue, block); 463 } else { 464 return currentValue; 465 } 466 } 467 468 private ValuePhiNode createValuePhi(ValueNode currentValue, ValueNode otherValue, AbstractMergeNode block) { 469 ValuePhiNode phi = graph.addWithoutUnique(new ValuePhiNode(currentValue.stamp(NodeView.DEFAULT).unrestricted(), block)); 470 for (int i = 0; i < block.phiPredecessorCount(); i++) { 471 phi.addInput(currentValue); 472 } 473 phi.addInput(otherValue); 474 assert phi.valueCount() == block.phiPredecessorCount() + 1; 475 return phi; 476 } 477 478 public void inferPhiStamps(AbstractMergeNode block) { 479 for (int i = 0; i < localsSize(); i++) { 480 inferPhiStamp(block, locals[i]); 481 } 482 for (int i = 0; i < stackSize(); i++) { 483 inferPhiStamp(block, stack[i]); 484 } 485 for (int i = 0; i < lockedObjects.length; i++) { 486 inferPhiStamp(block, lockedObjects[i]); 487 } 488 } 489 490 private static void inferPhiStamp(AbstractMergeNode block, ValueNode node) { 491 if (block.isPhiAtMerge(node)) { 492 node.inferStamp(); 493 } 494 } 495 496 public void insertLoopPhis(LocalLiveness liveness, int loopId, LoopBeginNode loopBegin, boolean forcePhis, boolean stampFromValueForForcedPhis) { 497 for (int i = 0; i < localsSize(); i++) { 498 boolean changedInLoop = liveness.localIsChangedInLoop(loopId, i); 499 if (forcePhis || changedInLoop) { 500 locals[i] = createLoopPhi(loopBegin, locals[i], stampFromValueForForcedPhis && !changedInLoop); 501 } 502 } 503 for (int i = 0; i < stackSize(); i++) { 504 stack[i] = createLoopPhi(loopBegin, stack[i], false); 505 } 506 for (int i = 0; i < lockedObjects.length; i++) { 507 lockedObjects[i] = createLoopPhi(loopBegin, lockedObjects[i], false); 508 } 509 } 510 511 public void insertLoopProxies(LoopExitNode loopExit, FrameStateBuilder loopEntryState) { 512 DebugContext debug = graph.getDebug(); 513 for (int i = 0; i < localsSize(); i++) { 514 ValueNode value = locals[i]; 515 if (value != null && value != TWO_SLOT_MARKER && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) { 516 debug.log(" inserting proxy for %s", value); 517 locals[i] = ProxyNode.forValue(value, loopExit, graph); 518 } 519 } 520 for (int i = 0; i < stackSize(); i++) { 521 ValueNode value = stack[i]; 522 if (value != null && value != TWO_SLOT_MARKER && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) { 523 debug.log(" inserting proxy for %s", value); 524 stack[i] = ProxyNode.forValue(value, loopExit, graph); 525 } 526 } 527 for (int i = 0; i < lockedObjects.length; i++) { 528 ValueNode value = lockedObjects[i]; 529 if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) { 530 debug.log(" inserting proxy for %s", value); 531 lockedObjects[i] = ProxyNode.forValue(value, loopExit, graph); 532 } 533 } 534 } 535 536 public void insertProxies(Function<ValueNode, ValueNode> proxyFunction) { 537 DebugContext debug = graph.getDebug(); 538 for (int i = 0; i < localsSize(); i++) { 539 ValueNode value = locals[i]; 540 if (value != null && value != TWO_SLOT_MARKER) { 541 debug.log(" inserting proxy for %s", value); 542 locals[i] = proxyFunction.apply(value); 543 } 544 } 545 for (int i = 0; i < stackSize(); i++) { 546 ValueNode value = stack[i]; 547 if (value != null && value != TWO_SLOT_MARKER) { 548 debug.log(" inserting proxy for %s", value); 549 stack[i] = proxyFunction.apply(value); 550 } 551 } 552 for (int i = 0; i < lockedObjects.length; i++) { 553 ValueNode value = lockedObjects[i]; 554 if (value != null) { 555 debug.log(" inserting proxy for %s", value); 556 lockedObjects[i] = proxyFunction.apply(value); 557 } 558 } 559 } 560 561 private ValueNode createLoopPhi(AbstractMergeNode block, ValueNode value, boolean stampFromValue) { 562 if (value == null || value == TWO_SLOT_MARKER) { 563 return value; 564 } 565 assert !block.isPhiAtMerge(value) : "phi function for this block already created"; 566 567 ValuePhiNode phi = graph.addWithoutUnique(new ValuePhiNode(stampFromValue ? value.stamp(NodeView.DEFAULT) : value.stamp(NodeView.DEFAULT).unrestricted(), block)); 568 phi.addInput(value); 569 return phi; 570 } 571 572 /** 573 * Adds a locked monitor to this frame state. 574 * 575 * @param object the object whose monitor will be locked. 576 */ 577 public void pushLock(ValueNode object, MonitorIdNode monitorId) { 578 assert object.isAlive() && object.getStackKind() == JavaKind.Object : "unexpected value: " + object; 579 lockedObjects = Arrays.copyOf(lockedObjects, lockedObjects.length + 1); 580 monitorIds = Arrays.copyOf(monitorIds, monitorIds.length + 1); 581 lockedObjects[lockedObjects.length - 1] = object; 582 monitorIds[monitorIds.length - 1] = monitorId; 583 assert lockedObjects.length == monitorIds.length; 584 } 585 586 /** 587 * Removes a locked monitor from this frame state. 588 * 589 * @return the object whose monitor was removed from the locks list. 590 */ 591 public ValueNode popLock() { 592 try { 593 return lockedObjects[lockedObjects.length - 1]; 594 } finally { 595 lockedObjects = lockedObjects.length == 1 ? EMPTY_ARRAY : Arrays.copyOf(lockedObjects, lockedObjects.length - 1); 596 monitorIds = monitorIds.length == 1 ? EMPTY_MONITOR_ARRAY : Arrays.copyOf(monitorIds, monitorIds.length - 1); 597 assert lockedObjects.length == monitorIds.length; 598 } 599 } 600 601 public MonitorIdNode peekMonitorId() { 602 return monitorIds[monitorIds.length - 1]; 603 } 604 605 /** 606 * @return the current lock depth 607 */ 608 public int lockDepth(boolean includeParents) { 609 int depth = lockedObjects.length; 610 assert depth == monitorIds.length; 611 if (includeParents && parser.getParent() != null) { 612 depth += parser.getParent().frameState.lockDepth(true); 613 } 614 return depth; 615 } 616 617 public boolean contains(ValueNode value) { 618 for (int i = 0; i < localsSize(); i++) { 619 if (locals[i] == value) { 620 return true; 621 } 622 } 623 for (int i = 0; i < stackSize(); i++) { 624 if (stack[i] == value) { 625 return true; 626 } 627 } 628 assert lockedObjects.length == monitorIds.length; 629 for (int i = 0; i < lockedObjects.length; i++) { 630 if (lockedObjects[i] == value || monitorIds[i] == value) { 631 return true; 632 } 633 } 634 return false; 635 } 636 637 public void clearNonLiveLocals(BciBlock block, LocalLiveness liveness, boolean liveIn) { 638 /* 639 * Non-live local clearing is mandatory for the entry block of an OSR compilation so that 640 * dead object slots at the OSR entry are cleared. It's not sufficient to rely on PiNodes 641 * with Kind.Illegal, because the conflicting branch might not have been parsed. 642 */ 643 boolean isOSREntryBlock = graph.isOSR() && getMethod().equals(graph.method()) && graph.getEntryBCI() == block.startBci; 644 if (!clearNonLiveLocals && !isOSREntryBlock) { 645 return; 646 } 647 if (liveIn) { 648 for (int i = 0; i < locals.length; i++) { 649 if (!liveness.localIsLiveIn(block, i)) { 650 assert locals[i] != TWO_SLOT_MARKER || locals[i - 1] == null : "Clearing of second slot must have cleared the first slot too"; 651 locals[i] = null; 652 } 653 } 654 } else { 655 for (int i = 0; i < locals.length; i++) { 656 if (!liveness.localIsLiveOut(block, i)) { 657 assert locals[i] != TWO_SLOT_MARKER || locals[i - 1] == null : "Clearing of second slot must have cleared the first slot too"; 658 locals[i] = null; 659 } 660 } 661 } 662 } 663 664 /** 665 * Clears all local variables. 666 */ 667 public void clearLocals() { 668 for (int i = 0; i < locals.length; i++) { 669 locals[i] = null; 670 } 671 } 672 673 /** 674 * @see BytecodeFrame#rethrowException 675 */ 676 public boolean rethrowException() { 677 return rethrowException; 678 } 679 680 /** 681 * @see BytecodeFrame#rethrowException 682 */ 683 public void setRethrowException(boolean b) { 684 rethrowException = b; 685 } 686 687 /** 688 * Returns the size of the local variables. 689 * 690 * @return the size of the local variables 691 */ 692 public int localsSize() { 693 return locals.length; 694 } 695 696 /** 697 * Gets the current size (height) of the stack. 698 */ 699 public int stackSize() { 700 return stackSize; 701 } 702 703 private boolean verifyKind(JavaKind slotKind, ValueNode x) { 704 assert x != null; 705 assert x != TWO_SLOT_MARKER; 706 assert slotKind.getSlotCount() > 0; 707 708 if (canVerifyKind) { 709 assert x.getStackKind() == slotKind.getStackKind(); 710 } 711 return true; 712 } 713 714 /** 715 * Loads the local variable at the specified index, checking that the returned value is non-null 716 * and that two-stack values are properly handled. 717 * 718 * @param i the index of the local variable to load 719 * @param slotKind the kind of the local variable from the point of view of the bytecodes 720 * @return the instruction that produced the specified local 721 */ 722 public ValueNode loadLocal(int i, JavaKind slotKind) { 723 ValueNode x = locals[i]; 724 assert verifyKind(slotKind, x); 725 assert slotKind.needsTwoSlots() ? locals[i + 1] == TWO_SLOT_MARKER : (i == locals.length - 1 || locals[i + 1] != TWO_SLOT_MARKER); 726 return x; 727 } 728 729 /** 730 * Stores a given local variable at the specified index. If the value occupies two slots, then 731 * the next local variable index is also overwritten. 732 * 733 * @param i the index at which to store 734 * @param slotKind the kind of the local variable from the point of view of the bytecodes 735 * @param x the instruction which produces the value for the local 736 */ 737 public void storeLocal(int i, JavaKind slotKind, ValueNode x) { 738 assert verifyKind(slotKind, x); 739 740 if (locals[i] == TWO_SLOT_MARKER) { 741 /* Writing the second slot of a two-slot value invalidates the first slot. */ 742 locals[i - 1] = null; 743 } 744 locals[i] = x; 745 if (slotKind.needsTwoSlots()) { 746 if (i < locals.length - 2 && locals[i + 2] == TWO_SLOT_MARKER) { 747 /* 748 * Writing a two-slot marker to an index previously occupied by a two-slot value: 749 * clear the old marker of the second slot. 750 */ 751 locals[i + 2] = null; 752 } 753 /* Writing a two-slot value: mark the second slot. */ 754 locals[i + 1] = TWO_SLOT_MARKER; 755 } else if (i < locals.length - 1 && locals[i + 1] == TWO_SLOT_MARKER) { 756 /* 757 * Writing a one-slot value to an index previously occupied by a two-slot value: clear 758 * the old marker of the second slot. 759 */ 760 locals[i + 1] = null; 761 } 762 } 763 764 /** 765 * Pushes an instruction onto the stack with the expected type. 766 * 767 * @param slotKind the kind of the stack element from the point of view of the bytecodes 768 * @param x the instruction to push onto the stack 769 */ 770 public void push(JavaKind slotKind, ValueNode x) { 771 assert verifyKind(slotKind, x); 772 773 xpush(x); 774 if (slotKind.needsTwoSlots()) { 775 xpush(TWO_SLOT_MARKER); 776 } 777 } 778 779 public void pushReturn(JavaKind slotKind, ValueNode x) { 780 if (slotKind != JavaKind.Void) { 781 push(slotKind, x); 782 } 783 } 784 785 /** 786 * Pops an instruction off the stack with the expected type. 787 * 788 * @param slotKind the kind of the stack element from the point of view of the bytecodes 789 * @return the instruction on the top of the stack 790 */ 791 public ValueNode pop(JavaKind slotKind) { 792 if (slotKind.needsTwoSlots()) { 793 ValueNode s = xpop(); 794 assert s == TWO_SLOT_MARKER; 795 } 796 ValueNode x = xpop(); 797 assert verifyKind(slotKind, x); 798 return x; 799 } 800 801 private void xpush(ValueNode x) { 802 assert x != null; 803 stack[stackSize++] = x; 804 } 805 806 private ValueNode xpop() { 807 ValueNode result = stack[--stackSize]; 808 assert result != null; 809 return result; 810 } 811 812 private ValueNode xpeek() { 813 ValueNode result = stack[stackSize - 1]; 814 assert result != null; 815 return result; 816 } 817 818 public ValueNode peekObject() { 819 ValueNode x = xpeek(); 820 assert verifyKind(JavaKind.Object, x); 821 return x; 822 } 823 824 /** 825 * Pop the specified number of slots off of this stack and return them as an array of 826 * instructions. 827 * 828 * @return an array containing the arguments off of the stack 829 */ 830 public ValueNode[] popArguments(int argSize) { 831 ValueNode[] result = allocateArray(argSize); 832 for (int i = argSize - 1; i >= 0; i--) { 833 ValueNode x = xpop(); 834 if (x == TWO_SLOT_MARKER) { 835 /* Ignore second slot of two-slot value. */ 836 x = xpop(); 837 } 838 assert x != null && x != TWO_SLOT_MARKER; 839 result[i] = x; 840 } 841 return result; 842 } 843 844 /** 845 * Clears all values on this stack. 846 */ 847 public void clearStack() { 848 stackSize = 0; 849 } 850 851 /** 852 * Performs a raw stack operation as defined in the Java bytecode specification. 853 * 854 * @param opcode The Java bytecode. 855 */ 856 public void stackOp(int opcode) { 857 switch (opcode) { 858 case POP: { 859 ValueNode w1 = xpop(); 860 assert w1 != TWO_SLOT_MARKER; 861 break; 862 } 863 case POP2: { 864 xpop(); 865 ValueNode w2 = xpop(); 866 assert w2 != TWO_SLOT_MARKER; 867 break; 868 } 869 case DUP: { 870 ValueNode w1 = xpeek(); 871 assert w1 != TWO_SLOT_MARKER; 872 xpush(w1); 873 break; 874 } 875 case DUP_X1: { 876 ValueNode w1 = xpop(); 877 ValueNode w2 = xpop(); 878 assert w1 != TWO_SLOT_MARKER; 879 xpush(w1); 880 xpush(w2); 881 xpush(w1); 882 break; 883 } 884 case DUP_X2: { 885 ValueNode w1 = xpop(); 886 ValueNode w2 = xpop(); 887 ValueNode w3 = xpop(); 888 assert w1 != TWO_SLOT_MARKER; 889 xpush(w1); 890 xpush(w3); 891 xpush(w2); 892 xpush(w1); 893 break; 894 } 895 case DUP2: { 896 ValueNode w1 = xpop(); 897 ValueNode w2 = xpop(); 898 xpush(w2); 899 xpush(w1); 900 xpush(w2); 901 xpush(w1); 902 break; 903 } 904 case DUP2_X1: { 905 ValueNode w1 = xpop(); 906 ValueNode w2 = xpop(); 907 ValueNode w3 = xpop(); 908 xpush(w2); 909 xpush(w1); 910 xpush(w3); 911 xpush(w2); 912 xpush(w1); 913 break; 914 } 915 case DUP2_X2: { 916 ValueNode w1 = xpop(); 917 ValueNode w2 = xpop(); 918 ValueNode w3 = xpop(); 919 ValueNode w4 = xpop(); 920 xpush(w2); 921 xpush(w1); 922 xpush(w4); 923 xpush(w3); 924 xpush(w2); 925 xpush(w1); 926 break; 927 } 928 case SWAP: { 929 ValueNode w1 = xpop(); 930 ValueNode w2 = xpop(); 931 assert w1 != TWO_SLOT_MARKER; 932 assert w2 != TWO_SLOT_MARKER; 933 xpush(w1); 934 xpush(w2); 935 break; 936 } 937 default: 938 throw shouldNotReachHere(); 939 } 940 } 941 942 @Override 943 public int hashCode() { 944 int result = hashCode(locals, locals.length); 945 result *= 13; 946 result += hashCode(stack, this.stackSize); 947 return result; 948 } 949 950 private static int hashCode(Object[] a, int length) { 951 int result = 1; 952 for (int i = 0; i < length; ++i) { 953 Object element = a[i]; 954 result = 31 * result + (element == null ? 0 : System.identityHashCode(element)); 955 } 956 return result; 957 } 958 959 private static boolean equals(ValueNode[] a, ValueNode[] b, int length) { 960 for (int i = 0; i < length; ++i) { 961 if (a[i] != b[i]) { 962 return false; 963 } 964 } 965 return true; 966 } 967 968 @Override 969 public boolean equals(Object otherObject) { 970 if (otherObject instanceof FrameStateBuilder) { 971 FrameStateBuilder other = (FrameStateBuilder) otherObject; 972 if (!other.code.equals(code)) { 973 return false; 974 } 975 if (other.stackSize != stackSize) { 976 return false; 977 } 978 if (other.parser != parser) { 979 return false; 980 } 981 if (other.tool != tool) { 982 return false; 983 } 984 if (other.rethrowException != rethrowException) { 985 return false; 986 } 987 if (other.graph != graph) { 988 return false; 989 } 990 if (other.locals.length != locals.length) { 991 return false; 992 } 993 return equals(other.locals, locals, locals.length) && equals(other.stack, stack, stackSize) && equals(other.lockedObjects, lockedObjects, lockedObjects.length) && 994 equals(other.monitorIds, monitorIds, monitorIds.length); 995 } 996 return false; 997 } 998 999 @Override 1000 public boolean isAfterSideEffect() { 1001 return sideEffects != null; 1002 } 1003 1004 @Override 1005 public Iterable<StateSplit> sideEffects() { 1006 return sideEffects; 1007 } 1008 1009 @Override 1010 public void addSideEffect(StateSplit sideEffect) { 1011 assert sideEffect != null; 1012 assert sideEffect.hasSideEffect(); 1013 if (sideEffects == null) { 1014 sideEffects = new ArrayList<>(4); 1015 } 1016 sideEffects.add(sideEffect); 1017 } 1018 }