Skip to content

Commit

Permalink
Allow deoptimization inside method handle.
Browse files Browse the repository at this point in the history
  • Loading branch information
mur47x111 committed Jun 4, 2020
1 parent aa51104 commit 508f050
Show file tree
Hide file tree
Showing 20 changed files with 288 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,11 @@ private void emitCodeSuffix(CompilationResultBuilder crb, AArch64MacroAssembler
ForeignCallLinkage linkage = foreignCalls.lookupForeignCall(DEOPT_BLOB_UNPACK);
masm.adr(lr, 0); // Warning: the argument is an offset from the instruction!
AArch64Call.directJmp(crb, masm, linkage);
if (config.supportsMethodHandleDeoptimizationEntry() && crb.needsMHDeoptHandler()) {
crb.recordMark(HotSpotMarkId.DEOPT_MH_HANDLER_ENTRY);
masm.adr(lr, 0);
AArch64Call.directJmp(crb, masm, linkage);
}
} else {
// No need to emit the stubs for entries back into the method since
// it has no calls that can cause such "return" entries
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;

import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.meta.Value;

Expand Down Expand Up @@ -69,6 +70,9 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
// correct inline cache value here.
crb.recordMark(invokeKind == InvokeKind.Static ? HotSpotMarkId.INVOKESTATIC : HotSpotMarkId.INVOKESPECIAL);
masm.movNativeAddress(inlineCacheRegister, config.nonOopBits);
if (config.supportsMethodHandleDeoptimizationEntry() && config.isMethodHandleCall((HotSpotResolvedJavaMethod) callTarget) && invokeKind != InvokeKind.Static) {
crb.setNeedsMHDeoptHandler();
}
super.emitCode(crb, masm);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;

import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.meta.Value;

Expand Down Expand Up @@ -69,6 +70,9 @@ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
// correct inline cache value here.
crb.recordMark(invokeKind == InvokeKind.Virtual ? HotSpotMarkId.INVOKEVIRTUAL : HotSpotMarkId.INVOKEINTERFACE);
masm.movNativeAddress(inlineCacheRegister, config.nonOopBits);
if (config.supportsMethodHandleDeoptimizationEntry() && config.isMethodHandleCall((HotSpotResolvedJavaMethod) callTarget)) {
crb.setNeedsMHDeoptHandler();
}
super.emitCode(crb, masm);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,10 @@ public void emitCodeSuffix(ResolvedJavaMethod installedCodeOwner, CompilationRes
AMD64Call.directCall(crb, asm, foreignCalls.lookupForeignCall(EXCEPTION_HANDLER), null, false, null);
crb.recordMark(HotSpotMarkId.DEOPT_HANDLER_ENTRY);
AMD64Call.directCall(crb, asm, foreignCalls.lookupForeignCall(DEOPT_BLOB_UNPACK), null, false, null);
if (config.supportsMethodHandleDeoptimizationEntry() && crb.needsMHDeoptHandler()) {
crb.recordMark(HotSpotMarkId.DEOPT_MH_HANDLER_ENTRY);
AMD64Call.directCall(crb, asm, foreignCalls.lookupForeignCall(DEOPT_BLOB_UNPACK), null, false, null);
}
} else {
// No need to emit the stubs for entries back into the method since
// it has no calls that can cause such "return" entries
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
package org.graalvm.compiler.hotspot.amd64;

import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
import org.graalvm.compiler.hotspot.HotSpotMarkId;
import org.graalvm.compiler.lir.LIRFrameState;
import org.graalvm.compiler.lir.LIRInstructionClass;
Expand All @@ -33,6 +34,7 @@
import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;

import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.meta.Value;

Expand All @@ -45,18 +47,23 @@ final class AMD64HotSpotDirectStaticCallOp extends DirectCallOp {
public static final LIRInstructionClass<AMD64HotSpotDirectStaticCallOp> TYPE = LIRInstructionClass.create(AMD64HotSpotDirectStaticCallOp.class);

private final InvokeKind invokeKind;
private final GraalHotSpotVMConfig config;

AMD64HotSpotDirectStaticCallOp(ResolvedJavaMethod target, Value result, Value[] parameters, Value[] temps, LIRFrameState state, InvokeKind invokeKind) {
AMD64HotSpotDirectStaticCallOp(ResolvedJavaMethod target, Value result, Value[] parameters, Value[] temps, LIRFrameState state, InvokeKind invokeKind, GraalHotSpotVMConfig config) {
super(TYPE, target, result, parameters, temps, state);
assert invokeKind.isDirect();
this.invokeKind = invokeKind;
this.config = config;
}

@Override
@SuppressWarnings("try")
public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
try (CompilationResultBuilder.CallContext callContext = crb.openCallContext(invokeKind.isDirect())) {
crb.recordMark(invokeKind == InvokeKind.Static ? HotSpotMarkId.INVOKESTATIC : HotSpotMarkId.INVOKESPECIAL);
if (config.supportsMethodHandleDeoptimizationEntry() && config.isMethodHandleCall((HotSpotResolvedJavaMethod) callTarget) && invokeKind != InvokeKind.Static) {
crb.setNeedsMHDeoptHandler();
}
super.emitCode(crb, masm);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ protected void emitDirectCall(DirectCallTargetNode callTarget, Value result, Val
assert invokeKind.isDirect();
HotSpotResolvedJavaMethod resolvedMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod();
assert resolvedMethod.isConcrete() : "Cannot make direct call to abstract method.";
append(new AMD64HotSpotDirectStaticCallOp(callTarget.targetMethod(), result, parameters, temps, callState, invokeKind));
append(new AMD64HotSpotDirectStaticCallOp(callTarget.targetMethod(), result, parameters, temps, callState, invokeKind, getGen().config));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;

import jdk.vm.ci.amd64.AMD64;
import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.meta.Value;

Expand Down Expand Up @@ -65,6 +66,9 @@ public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
crb.recordMark(invokeKind == InvokeKind.Virtual ? HotSpotMarkId.INVOKEVIRTUAL : HotSpotMarkId.INVOKEINTERFACE);
// This must be emitted exactly like this to ensure it's patchable
masm.movq(AMD64.rax, config.nonOopBits);
if (config.supportsMethodHandleDeoptimizationEntry() && config.isMethodHandleCall((HotSpotResolvedJavaMethod) callTarget)) {
crb.setNeedsMHDeoptHandler();
}
super.emitCall(crb, masm);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,10 @@ public void emitCode(CompilationResultBuilder crb, LIR lir, ResolvedJavaMethod i
SPARCCall.directCall(crb, masm, foreignCalls.lookupForeignCall(EXCEPTION_HANDLER), null, null);
crb.recordMark(HotSpotMarkId.DEOPT_HANDLER_ENTRY);
SPARCCall.directCall(crb, masm, foreignCalls.lookupForeignCall(DEOPT_BLOB_UNPACK), null, null);
if (config.supportsMethodHandleDeoptimizationEntry() && crb.needsMHDeoptHandler()) {
crb.recordMark(HotSpotMarkId.DEOPT_MH_HANDLER_ENTRY);
SPARCCall.directCall(crb, masm, foreignCalls.lookupForeignCall(DEOPT_BLOB_UNPACK), null, null);
}
} else {
// No need to emit the stubs for entries back into the method since
// it has no calls that can cause such "return" entries
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ protected void emitDirectCall(DirectCallTargetNode callTarget, Value result, Val
assert invokeKind.isDirect();
HotSpotResolvedJavaMethod resolvedMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod();
assert resolvedMethod.isConcrete() : "Cannot make direct call to abstract method.";
append(new SPARCHotspotDirectStaticCallOp(callTarget.targetMethod(), result, parameters, temps, callState, invokeKind));
append(new SPARCHotspotDirectStaticCallOp(callTarget.targetMethod(), result, parameters, temps, callState, invokeKind, getGen().config));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@
*/
package org.graalvm.compiler.hotspot.sparc;

import static jdk.vm.ci.sparc.SPARC.l7;
import static jdk.vm.ci.sparc.SPARC.sp;

import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
import org.graalvm.compiler.hotspot.HotSpotMarkId;
import org.graalvm.compiler.lir.LIRFrameState;
import org.graalvm.compiler.lir.LIRInstructionClass;
Expand All @@ -33,6 +37,7 @@
import org.graalvm.compiler.lir.sparc.SPARCCall.DirectCallOp;
import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;

import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.meta.Value;

Expand All @@ -46,16 +51,22 @@ final class SPARCHotspotDirectStaticCallOp extends DirectCallOp {
public static final SizeEstimate SIZE = SizeEstimate.create(8);

private final InvokeKind invokeKind;
private final GraalHotSpotVMConfig config;

SPARCHotspotDirectStaticCallOp(ResolvedJavaMethod target, Value result, Value[] parameters, Value[] temps, LIRFrameState state, InvokeKind invokeKind) {
SPARCHotspotDirectStaticCallOp(ResolvedJavaMethod target, Value result, Value[] parameters, Value[] temps, LIRFrameState state, InvokeKind invokeKind, GraalHotSpotVMConfig config) {
super(TYPE, SIZE, target, result, parameters, temps, state);
assert invokeKind.isDirect();
this.invokeKind = invokeKind;
this.config = config;
}

@Override
public void emitCallPrefixCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
crb.recordMark(invokeKind == InvokeKind.Static ? HotSpotMarkId.INVOKESTATIC : HotSpotMarkId.INVOKESPECIAL);
if (config.supportsMethodHandleDeoptimizationEntry() && config.isMethodHandleCall((HotSpotResolvedJavaMethod) callTarget) && invokeKind != InvokeKind.Static) {
crb.setNeedsMHDeoptHandler();
masm.mov(sp, l7);
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
package org.graalvm.compiler.hotspot.sparc;

import static jdk.vm.ci.sparc.SPARC.g5;
import static jdk.vm.ci.sparc.SPARC.l7;
import static jdk.vm.ci.sparc.SPARC.sp;

import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
Expand All @@ -37,6 +39,7 @@
import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;

import jdk.vm.ci.code.Register;
import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.meta.Value;

Expand Down Expand Up @@ -66,6 +69,10 @@ public void emitCallPrefixCode(CompilationResultBuilder crb, SPARCMacroAssembler
crb.recordMark(invokeKind == InvokeKind.Virtual ? HotSpotMarkId.INVOKEVIRTUAL : HotSpotMarkId.INVOKEINTERFACE);
Register scratchRegister = g5;
masm.setx(config.nonOopBits, scratchRegister, true);
if (config.supportsMethodHandleDeoptimizationEntry() && config.isMethodHandleCall((HotSpotResolvedJavaMethod) callTarget)) {
crb.setNeedsMHDeoptHandler();
masm.mov(sp, l7);
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.hotspot.test;

import java.io.IOException;
import java.util.List;

import org.graalvm.compiler.core.test.SubprocessTest;
import org.junit.Test;

public class HotSpotMethodHandleNonStaticCallTest extends SubprocessTest {

@Override
public void configSubprocess(List<String> vmArgs) {
// This will prevent inlining of the invocation to MethodHandle.invokeBasic at
// LambdaForm$MH.invoke_MT, and leave a virtual direct polymorphic signature
// call in the emitted code. We expect the PcDesc of this call to be with 'bits=2', i.e.,
// with the PCDESC_is_method_handle_invoke bit set.
vmArgs.add("-XX:CompileCommand=dontinline,java/lang/invoke/LambdaForm$DMH.invokeVirtual_L_V");
}

@Test
public void testInSubprocess() throws InterruptedException, IOException {
// To manually investigate, pass -DHotSpotMethodHandleNonStaticCallTest.Subprocess=true,
// -XX:CompileCommand='print,*.invokeDoNothing', and the added command at configSubprocess.
// You may need a fast debug hotspot build to view the PcDesc flags.
launchSubprocess(() -> test(getResolvedJavaMethod(HotSpotMethodHandleTest.class, "invokeDoNothing"), new HotSpotMethodHandleTest()));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.hotspot.test;

import java.io.IOException;
import java.util.List;

import org.graalvm.compiler.core.test.SubprocessTest;
import org.junit.Test;

public class HotSpotMethodHandleStaticCallTest extends SubprocessTest {

@Override
public void configSubprocess(List<String> vmArgs) {
// This will prevent inlining of the invocation to MethodHandle.invoke at
// HotSpotMethodHandleTest.invokeDoNothing, and leave a static direct polymorphic signature
// call in the emitted code. We expect the PcDesc of this call to be with 'bits=0', i.e.,
// with the PCDESC_is_method_handle_invoke bit unset.
vmArgs.add("-XX:CompileCommand=dontinline,java/lang/invoke/LambdaForm$MH.invoke_MT");
}

@Test
public void testInSubprocess() throws InterruptedException, IOException {
// To manually investigate, pass -DHotSpotMethodHandleStaticCallTest.Subprocess=true,
// -XX:CompileCommand='print,*.invokeDoNothing', and the added command at configSubprocess.
// You may need a fast debug hotspot build to view the PcDesc flags.
launchSubprocess(() -> test(getResolvedJavaMethod(HotSpotMethodHandleTest.class, "invokeDoNothing"), new HotSpotMethodHandleTest()));
}

}
Loading

0 comments on commit 508f050

Please sign in to comment.