1 /* |
1 /* |
2 * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. |
2 * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * |
4 * |
5 * This code is free software; you can redistribute it and/or modify it |
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 |
6 * under the terms of the GNU General Public License version 2 only, as |
7 * published by the Free Software Foundation. |
7 * published by the Free Software Foundation. |
33 import static org.graalvm.compiler.bytecode.Bytecodes.POP; |
33 import static org.graalvm.compiler.bytecode.Bytecodes.POP; |
34 import static org.graalvm.compiler.bytecode.Bytecodes.POP2; |
34 import static org.graalvm.compiler.bytecode.Bytecodes.POP2; |
35 import static org.graalvm.compiler.bytecode.Bytecodes.SWAP; |
35 import static org.graalvm.compiler.bytecode.Bytecodes.SWAP; |
36 import static org.graalvm.compiler.debug.GraalError.shouldNotReachHere; |
36 import static org.graalvm.compiler.debug.GraalError.shouldNotReachHere; |
37 import static org.graalvm.compiler.nodes.FrameState.TWO_SLOT_MARKER; |
37 import static org.graalvm.compiler.nodes.FrameState.TWO_SLOT_MARKER; |
|
38 import static org.graalvm.compiler.nodes.util.GraphUtil.originalValue; |
38 |
39 |
39 import java.util.ArrayList; |
40 import java.util.ArrayList; |
40 import java.util.Arrays; |
41 import java.util.Arrays; |
41 import java.util.List; |
42 import java.util.List; |
42 import java.util.function.Function; |
43 import java.util.function.Function; |
43 |
44 |
44 import org.graalvm.compiler.bytecode.Bytecode; |
45 import org.graalvm.compiler.bytecode.Bytecode; |
45 import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode; |
46 import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode; |
46 import org.graalvm.compiler.core.common.GraalOptions; |
|
47 import org.graalvm.compiler.core.common.PermanentBailoutException; |
47 import org.graalvm.compiler.core.common.PermanentBailoutException; |
48 import org.graalvm.compiler.core.common.type.StampFactory; |
48 import org.graalvm.compiler.core.common.type.StampFactory; |
49 import org.graalvm.compiler.core.common.type.StampPair; |
49 import org.graalvm.compiler.core.common.type.StampPair; |
50 import org.graalvm.compiler.debug.DebugContext; |
50 import org.graalvm.compiler.debug.DebugContext; |
51 import org.graalvm.compiler.debug.GraalError; |
51 import org.graalvm.compiler.debug.GraalError; |
69 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; |
69 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; |
70 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderTool; |
70 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderTool; |
71 import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.SideEffectsState; |
71 import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.SideEffectsState; |
72 import org.graalvm.compiler.nodes.graphbuilderconf.ParameterPlugin; |
72 import org.graalvm.compiler.nodes.graphbuilderconf.ParameterPlugin; |
73 import org.graalvm.compiler.nodes.java.MonitorIdNode; |
73 import org.graalvm.compiler.nodes.java.MonitorIdNode; |
74 import org.graalvm.compiler.nodes.util.GraphUtil; |
|
75 |
74 |
76 import jdk.vm.ci.code.BytecodeFrame; |
75 import jdk.vm.ci.code.BytecodeFrame; |
77 import jdk.vm.ci.meta.Assumptions; |
76 import jdk.vm.ci.meta.Assumptions; |
78 import jdk.vm.ci.meta.JavaKind; |
77 import jdk.vm.ci.meta.JavaKind; |
79 import jdk.vm.ci.meta.JavaType; |
78 import jdk.vm.ci.meta.JavaType; |
273 assert other.graph != null; |
272 assert other.graph != null; |
274 graph = other.graph; |
273 graph = other.graph; |
275 clearNonLiveLocals = other.clearNonLiveLocals; |
274 clearNonLiveLocals = other.clearNonLiveLocals; |
276 monitorIds = other.monitorIds.length == 0 ? other.monitorIds : other.monitorIds.clone(); |
275 monitorIds = other.monitorIds.length == 0 ? other.monitorIds : other.monitorIds.clone(); |
277 |
276 |
278 assert locals.length == code.getMaxLocals(); |
|
279 assert stack.length == Math.max(1, code.getMaxStackSize()); |
|
280 assert lockedObjects.length == monitorIds.length; |
277 assert lockedObjects.length == monitorIds.length; |
281 } |
278 } |
282 |
279 |
283 private static ValueNode[] allocateArray(int length) { |
280 private static ValueNode[] allocateArray(int length) { |
284 return length == 0 ? EMPTY_ARRAY : new ValueNode[length]; |
281 return length == 0 ? EMPTY_ARRAY : new ValueNode[length]; |
385 |
382 |
386 public FrameStateBuilder copy() { |
383 public FrameStateBuilder copy() { |
387 return new FrameStateBuilder(this); |
384 return new FrameStateBuilder(this); |
388 } |
385 } |
389 |
386 |
390 public boolean isCompatibleWith(FrameStateBuilder other) { |
387 private String incompatibilityErrorMessage(String reason, FrameStateBuilder other) { |
|
388 return String.format("Frame states being merged are incompatible: %s%n This frame state: %s%nOther frame state: %s%nParser context: %s", reason, this, other, parser); |
|
389 } |
|
390 |
|
391 /** |
|
392 * Checks invariants that must hold when merging {@code other} into this frame state. |
|
393 * |
|
394 * @param other |
|
395 * @throws PermanentBailoutException if the frame states are incompatible with respect to their |
|
396 * locked objects. This indicates bytecode that has unstructured or unbalanced |
|
397 * locks. |
|
398 * @throws GraalError if the frame states are incompatible in terms of {@link #rethrowException} |
|
399 * or stack slots |
|
400 */ |
|
401 public void checkCompatibleWith(FrameStateBuilder other) { |
391 assert code.equals(other.code) && graph == other.graph && localsSize() == other.localsSize() : "Can only compare frame states of the same method"; |
402 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"; |
403 assert lockedObjects.length == monitorIds.length && other.lockedObjects.length == other.monitorIds.length : "mismatch between lockedObjects and monitorIds"; |
393 |
404 |
394 if (rethrowException != other.rethrowException) { |
405 if (rethrowException != other.rethrowException) { |
395 return false; |
406 throw new GraalError(incompatibilityErrorMessage("mismatch in rethrowException flag", other)); |
396 } |
407 } |
397 |
408 |
398 if (stackSize() != other.stackSize()) { |
409 if (stackSize() != other.stackSize()) { |
399 return false; |
410 throw new GraalError(incompatibilityErrorMessage("mismatch in stack sizes", other)); |
400 } |
411 } |
401 for (int i = 0; i < stackSize(); i++) { |
412 for (int i = 0; i < stackSize(); i++) { |
402 ValueNode x = stack[i]; |
413 ValueNode x = stack[i]; |
403 ValueNode y = other.stack[i]; |
414 ValueNode y = other.stack[i]; |
404 assert x != null && y != null; |
415 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())) { |
416 if (x != y && (x == TWO_SLOT_MARKER || x.isDeleted() || y == TWO_SLOT_MARKER || y.isDeleted() || x.getStackKind() != y.getStackKind())) { |
406 return false; |
417 throw new GraalError(incompatibilityErrorMessage("mismatch in stack types", other)); |
407 } |
418 } |
408 } |
419 } |
409 if (lockedObjects.length != other.lockedObjects.length) { |
420 if (lockedObjects.length != other.lockedObjects.length) { |
410 return false; |
421 throw new PermanentBailoutException(incompatibilityErrorMessage("unbalanced monitors - locked objects do not match", other)); |
411 } |
422 } |
412 for (int i = 0; i < lockedObjects.length; i++) { |
423 for (int i = 0; i < lockedObjects.length; i++) { |
413 if (GraphUtil.originalValue(lockedObjects[i]) != GraphUtil.originalValue(other.lockedObjects[i]) || monitorIds[i] != other.monitorIds[i]) { |
424 if (originalValue(lockedObjects[i], false) != originalValue(other.lockedObjects[i], false)) { |
414 throw new PermanentBailoutException("unbalanced monitors"); |
425 throw new PermanentBailoutException(incompatibilityErrorMessage("unbalanced monitors - locked objects do not match", other)); |
415 } |
426 } |
416 } |
427 if (monitorIds[i] != other.monitorIds[i]) { |
417 return true; |
428 throw new PermanentBailoutException(incompatibilityErrorMessage("unbalanced monitors - monitors do not match", other)); |
|
429 } |
|
430 } |
418 } |
431 } |
419 |
432 |
420 public void merge(AbstractMergeNode block, FrameStateBuilder other) { |
433 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); |
434 checkCompatibleWith(other); |
422 |
435 |
423 for (int i = 0; i < localsSize(); i++) { |
436 for (int i = 0; i < localsSize(); i++) { |
424 locals[i] = merge(locals[i], other.locals[i], block); |
437 locals[i] = merge(locals[i], other.locals[i], block); |
425 } |
438 } |
426 for (int i = 0; i < stackSize(); i++) { |
439 for (int i = 0; i < stackSize(); i++) { |