From 1c981d854fc1e044949dcdd96fc94de8aaa14b49 Mon Sep 17 00:00:00 2001 From: ChengJin01 Date: Fri, 24 Nov 2023 20:12:46 -0500 Subject: [PATCH] [FFI/JDKnext] Perf improvement via NativeMethodHandle/linkToNative The changes aim to generate the NativeMethodHandle instance to ensure the invocation path goes via linkToNative. Signed-off-by: ChengJin01 --- .../java/lang/invoke/MethodHandleImpl.java | 4 +- .../java/lang/invoke/NativeMethodHandle.java | 42 +++++++++++++++---- .../internal/access/JavaLangInvokeAccess.java | 8 +++- 3 files changed, 42 insertions(+), 12 deletions(-) diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java b/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java index aa341b5a632..1d9bbbb787e 100644 --- a/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java @@ -25,7 +25,7 @@ /* * =========================================================================== - * (c) Copyright IBM Corp. 2022, 2022 All Rights Reserved + * (c) Copyright IBM Corp. 2022, 2024 All Rights Reserved * =========================================================================== */ @@ -1580,7 +1580,7 @@ public VarHandle memorySegmentViewHandle(Class carrier, long alignmentMask, B } @Override - public MethodHandle nativeMethodHandle(NativeEntryPoint nep) { + public MethodHandle nativeMethodHandle(MethodHandle nep) { return NativeMethodHandle.make(nep); } diff --git a/src/java.base/share/classes/java/lang/invoke/NativeMethodHandle.java b/src/java.base/share/classes/java/lang/invoke/NativeMethodHandle.java index 4d09b96775d..52909dd63aa 100644 --- a/src/java.base/share/classes/java/lang/invoke/NativeMethodHandle.java +++ b/src/java.base/share/classes/java/lang/invoke/NativeMethodHandle.java @@ -23,8 +23,17 @@ * questions. */ +/* + * =========================================================================== + * (c) Copyright IBM Corp. 2023, 2024 All Rights Reserved + * =========================================================================== + */ + package java.lang.invoke; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; + import jdk.internal.vm.annotation.ForceInline; import jdk.internal.foreign.abi.NativeEntryPoint; @@ -34,23 +43,29 @@ import static java.lang.invoke.MethodHandleStatics.newInternalError; /** - * This class models a method handle to a native function. A native method handle is made up of a {@link NativeEntryPoint}, + * This class models a method handle to a native function. A native method handle is made up of a bound {@link MethodHandle}, * which is used to capture the characteristics of the native call (such as calling convention to be used, * or whether a native transition is required) and a fallback method handle, which can be used * when intrinsification of this method handle is not possible. */ /*non-public*/ final class NativeMethodHandle extends MethodHandle { - final NativeEntryPoint nep; + /* The native entry point is literally the bound MethodHandle implemented in OpenJ9. */ + final MethodHandle nep; + + /* The cache array for the bound MethodHandle stores MemberName and appendix which are populated + * by MethodHandleResolver.ffiCallLinkCallerMethod(). + */ + private Object[] invokeCache; - private NativeMethodHandle(MethodType type, LambdaForm form, NativeEntryPoint nep) { + private NativeMethodHandle(MethodType type, LambdaForm form, MethodHandle nep) { super(type, form); this.nep = nep; } /** - * Creates a new native method handle with given {@link NativeEntryPoint} and fallback method handle. + * Creates a new native method handle with given {@link MethodHandle} and fallback method handle. */ - public static MethodHandle make(NativeEntryPoint nep) { + public static MethodHandle make(MethodHandle nep) { MethodType type = nep.type(); if (hasIllegalType(type)) throw new IllegalArgumentException("Illegal type(s) found: " + type); @@ -78,7 +93,9 @@ private static boolean isIllegalType(Class pType) { || pType == float.class || pType == double.class || pType == void.class - || pType == Object.class); + || pType == Object.class + || pType == MemorySegment.class // Skip checking the argument preset in OpenJ9 for the moment. + || pType == SegmentAllocator.class); // Skip checking the argument preset OpenJ9 for the moment. } private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory(); @@ -93,8 +110,12 @@ private static LambdaForm preparedLambdaForm(MethodType mtype) { } private static LambdaForm makePreparedLambdaForm(MethodType mtype) { + /* The NativeMethodHandle object must be appended to the end of the argument + * list to ensure the invoke cache of the bound MH is correctly fetched + * from linkToNative in the interpreter. + */ MethodType linkerType = mtype - .appendParameterTypes(Object.class); // NEP + .appendParameterTypes(Object.class); // the NativeMethodHandle object MemberName linker = new MemberName(MethodHandle.class, "linkToNative", linkerType, REF_invokeStatic); try { linker = IMPL_NAMES.resolveOrFail(REF_invokeStatic, linker, null, LM_TRUSTED, NoSuchMethodException.class); @@ -137,8 +158,11 @@ BoundMethodHandle rebind() { } @ForceInline - static Object internalNativeEntryPoint(Object mh) { - return ((NativeMethodHandle)mh).nep; + static Object internalNativeEntryPoint(Object nativeMH) { + /* Return the nativeMH object as the argument passed over + * to linkToNative in the LambdaForm-generated bytecode. + */ + return nativeMH; } /** diff --git a/src/java.base/share/classes/jdk/internal/access/JavaLangInvokeAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaLangInvokeAccess.java index 563870381fe..a090a8ea4da 100644 --- a/src/java.base/share/classes/jdk/internal/access/JavaLangInvokeAccess.java +++ b/src/java.base/share/classes/jdk/internal/access/JavaLangInvokeAccess.java @@ -23,6 +23,12 @@ * questions. */ +/* + * =========================================================================== + * (c) Copyright IBM Corp. 2023, 2024 All Rights Reserved + * =========================================================================== + */ + package jdk.internal.access; import jdk.internal.foreign.abi.NativeEntryPoint; @@ -121,7 +127,7 @@ public interface JavaLangInvokeAccess { * @param nep the native entry point * @return the native method handle */ - MethodHandle nativeMethodHandle(NativeEntryPoint nep); + MethodHandle nativeMethodHandle(MethodHandle nep); /** * Produces a method handle unreflecting from a {@code Constructor} with