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