Skip to content

Commit b51e7bc

Browse files
committed
Fix underflow in MethodHandlePlugin
1 parent 85d0a8e commit b51e7bc

File tree

4 files changed

+34
-16
lines changed

4 files changed

+34
-16
lines changed

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/java/BytecodeParser.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2948,6 +2948,11 @@ private <T extends Node> void updateLastInstruction(T v) {
29482948
}
29492949
}
29502950

2951+
@Override
2952+
public boolean hasParseTerminated() {
2953+
return lastInstr == null;
2954+
}
2955+
29512956
private AbstractBeginNode updateWithExceptionNode(WithExceptionNode withExceptionNode) {
29522957
if (withExceptionNode.exceptionEdge() == null) {
29532958
AbstractBeginNode exceptionEdge = handleException(null, bci(), false);

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/nodes/graphbuilderconf/GraphBuilderContext.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,13 @@ default boolean parsingIntrinsic() {
301301
return getIntrinsic() != null;
302302
}
303303

304+
/**
305+
* Returns true if control flow has terminated in some fashion, such as a deoptimization.
306+
*/
307+
default boolean hasParseTerminated() {
308+
throw GraalError.unimplementedParent(); // ExcludeFromJacocoGeneratedReport
309+
}
310+
304311
/**
305312
* Determines if a graph builder plugin is enabled under current context.
306313
*/

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/IntrinsicGraphBuilder.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,11 @@ private <T extends Node> void updateLastInstruction(T v) {
195195
}
196196
}
197197

198+
@Override
199+
public boolean hasParseTerminated() {
200+
return lastInstr == null;
201+
}
202+
198203
@Override
199204
public AbstractBeginNode genExplicitExceptionEdge(BytecodeExceptionNode.BytecodeExceptionKind exceptionKind, ValueNode... exceptionArguments) {
200205
BytecodeExceptionNode exceptionNode = graph.add(new BytecodeExceptionNode(getMetaAccess(), exceptionKind, exceptionArguments));

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/MethodHandlePlugin.java

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@
4242
import jdk.graal.compiler.replacements.nodes.MacroNode;
4343
import jdk.graal.compiler.replacements.nodes.MethodHandleNode;
4444
import jdk.graal.compiler.replacements.nodes.ResolvedMethodHandleCallTargetNode;
45-
4645
import jdk.vm.ci.meta.JavaKind;
4746
import jdk.vm.ci.meta.MethodHandleAccessProvider;
4847
import jdk.vm.ci.meta.MethodHandleAccessProvider.IntrinsicMethod;
@@ -129,21 +128,23 @@ public <T extends ValueNode> T add(T node) {
129128
}
130129
}
131130

132-
/*
133-
* After handleReplacedInvoke, a return type according to the signature of
134-
* targetMethod has been pushed. That can be different than the type expected by the
135-
* method handle invoke. Since there cannot be any implicit type conversion, the
136-
* only safe option actually is that the return type is not used at all. If there is
137-
* any other expected return type, the bytecodes are wrong. The JavaDoc of
138-
* MethodHandle.invokeBasic states that this "could crash the JVM", so bailing out
139-
* of compilation seems like a good idea.
140-
*/
141-
JavaKind invokeReturnKind = invokeReturnStamp.getTrustedStamp().getStackKind();
142-
JavaKind targetMethodReturnKind = targetMethod.getSignature().getReturnKind().getStackKind();
143-
if (invokeReturnKind != targetMethodReturnKind) {
144-
b.pop(targetMethodReturnKind);
145-
if (invokeReturnKind != JavaKind.Void) {
146-
throw b.bailout("Cannot do any type conversion when invoking method handle, so return value must remain popped");
131+
if (!b.hasParseTerminated()) {
132+
/*
133+
* After handleReplacedInvoke, a return type according to the signature of
134+
* targetMethod has been pushed. That can be different than the type expected by
135+
* the method handle invoke. Since there cannot be any implicit type conversion,
136+
* the only safe option actually is that the return type is not used at all. If
137+
* there is any other expected return type, the bytecodes are wrong. The JavaDoc
138+
* of MethodHandle.invokeBasic states that this "could crash the JVM", so
139+
* bailing out of compilation seems like a good idea.
140+
*/
141+
JavaKind invokeReturnKind = invokeReturnStamp.getTrustedStamp().getStackKind();
142+
JavaKind targetMethodReturnKind = targetMethod.getSignature().getReturnKind().getStackKind();
143+
if (invokeReturnKind != targetMethodReturnKind) {
144+
b.pop(targetMethodReturnKind);
145+
if (invokeReturnKind != JavaKind.Void) {
146+
throw b.bailout("Cannot do any type conversion when invoking method handle, so return value must remain popped");
147+
}
147148
}
148149
}
149150
}

0 commit comments

Comments
 (0)