From f247003403c25d538ac1f940119ea8b31c7df7a6 Mon Sep 17 00:00:00 2001 From: Nazim Bhuiyan Date: Wed, 6 Nov 2024 15:26:03 -0500 Subject: [PATCH] Enable inlining of non-native Unsafe unaligned getters and setters For Unsafe_getXUnaligned methods, which are wrappers to native methods that contain some runtime checks, we benefit from directly inlining them in inlineUnsafeCall as if they were their underlying native methods, if we can determine that it is safe to do so. This commit introduces the changes necessary to correctly handle such non-native unaligned getters and setters, and enables transforming them to simple loads and stores based on whether the platform supports aligned access only. Signed-off-by: Nazim Bhuiyan --- .../compiler/optimizer/InlinerTempForJ9.cpp | 41 +++++++++++++++---- runtime/compiler/optimizer/J9Inliner.hpp | 16 ++++++++ 2 files changed, 49 insertions(+), 8 deletions(-) diff --git a/runtime/compiler/optimizer/InlinerTempForJ9.cpp b/runtime/compiler/optimizer/InlinerTempForJ9.cpp index d391c92cc9c..9337957871b 100644 --- a/runtime/compiler/optimizer/InlinerTempForJ9.cpp +++ b/runtime/compiler/optimizer/InlinerTempForJ9.cpp @@ -1399,8 +1399,7 @@ TR_J9InlinerPolicy::createUnsafePutWithOffset(TR::ResolvedMethodSymbol *calleeSy if (isVolatile && type == TR::Int64 && comp()->target().is32Bit() && !comp()->cg()->getSupportsInlinedAtomicLongVolatiles()) return false; - // In general, Z does not permit unaligned accesses - if (isUnaligned && comp()->target().cpu.isZ()) + if (isUnaligned && comp()->cg()->getSupportsAlignedAccessOnly()) return false; if (debug("traceUnsafe")) @@ -1990,7 +1989,7 @@ TR_J9InlinerPolicy::createUnsafeGetWithOffset(TR::ResolvedMethodSymbol *calleeSy if (isVolatile && type == TR::Int64 && comp()->target().is32Bit() && !comp()->cg()->getSupportsInlinedAtomicLongVolatiles()) return false; - if (isUnaligned && comp()->target().cpu.isZ()) + if (isUnaligned && comp()->cg()->getSupportsAlignedAccessOnly()) return false; if (debug("traceUnsafe")) @@ -2603,13 +2602,13 @@ TR_J9InlinerPolicy::inlineUnsafeCall(TR::ResolvedMethodSymbol *calleeSymbol, TR: // FIXME: Update createUnsafePutWithOffset signature to have isVolatile, isOrdered, isUnaligned as enum case TR::jdk_internal_misc_Unsafe_getCharUnaligned: - return createUnsafeGetWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int8, /*needsNullCheck*/false, /*isUnaligned*/true); + return createUnsafeGetWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int16, /*isVolatile*/false, /*needsNullCheck*/false, /*isUnaligned*/true); case TR::jdk_internal_misc_Unsafe_getShortUnaligned: - return createUnsafeGetWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int16, /*needsNullCheck*/false, /*isUnaligned*/true); + return createUnsafeGetWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int16, /*isVolatile*/false, /*needsNullCheck*/false, /*isUnaligned*/true); case TR::jdk_internal_misc_Unsafe_getIntUnaligned: - return createUnsafeGetWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int32, /*needsNullCheck*/false, /*isUnaligned*/true); + return createUnsafeGetWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int32, /*isVolatile*/false, /*needsNullCheck*/false, /*isUnaligned*/true); case TR::jdk_internal_misc_Unsafe_getLongUnaligned: - return createUnsafeGetWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int64, /*needsNullCheck*/false, /*isUnaligned*/true); + return createUnsafeGetWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int64, /*isVolatile*/false, /*needsNullCheck*/false, /*isUnaligned*/true); case TR::jdk_internal_misc_Unsafe_putCharUnaligned: return createUnsafePutWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int8, /*isVolatile*/false, /*needsNullCheck*/false, /*isOrdered*/false, /*isUnaligned*/true); case TR::jdk_internal_misc_Unsafe_putShortUnaligned: @@ -2784,8 +2783,12 @@ TR_J9InlinerPolicy::isInlineableJNI(TR_ResolvedMethod *method,TR::Node *callNode // In Java9 sun/misc/Unsafe methods are simple Java wrappers to JNI // methods in jdk.internal, and the enum values above match both. Only // return true for the methods that are native. + // In the case of Unsafe_getXUnaligned methods, which are also wrappers to + // native methods that contain some runtime checks, we benefit from directly + // inlining them in inlineUnsafeCall as if they were their underlying native + // methods, if we can determine that it is safe to do so. if (!TR::Compiler->om.canGenerateArraylets() || (callNode && callNode->isUnsafeGetPutCASCallOnNonArray())) - return method->isNative(); + return method->isNative() || isSimpleWrapperForInlineableUnsafeNativeMethod(method); else return false; } @@ -6039,6 +6042,28 @@ bool TR_J9InlinerPolicy::isJSR292SmallGetterMethod(TR_ResolvedMethod *resolvedMe return false; } +bool +TR_J9InlinerPolicy::isSimpleWrapperForInlineableUnsafeNativeMethod(TR_ResolvedMethod *resolvedMethod) + { + TR::RecognizedMethod method = resolvedMethod->getRecognizedMethod(); + switch (method) + { + case TR::jdk_internal_misc_Unsafe_getCharUnaligned: + case TR::jdk_internal_misc_Unsafe_getShortUnaligned: + case TR::jdk_internal_misc_Unsafe_getIntUnaligned: + case TR::jdk_internal_misc_Unsafe_getLongUnaligned: + case TR::jdk_internal_misc_Unsafe_putCharUnaligned: + case TR::jdk_internal_misc_Unsafe_putShortUnaligned: + case TR::jdk_internal_misc_Unsafe_putIntUnaligned: + case TR::jdk_internal_misc_Unsafe_putLongUnaligned: + return true; + + default: + break; + } + return false; + } + void TR_J9InlinerUtil::estimateAndRefineBytecodeSize(TR_CallSite* callsite, TR_CallTarget* calltarget, TR_CallStack *callStack, int32_t &bytecodeSize) { diff --git a/runtime/compiler/optimizer/J9Inliner.hpp b/runtime/compiler/optimizer/J9Inliner.hpp index 8e42a9650cb..b4fc015d607 100644 --- a/runtime/compiler/optimizer/J9Inliner.hpp +++ b/runtime/compiler/optimizer/J9Inliner.hpp @@ -358,6 +358,22 @@ class TR_J9InlinerPolicy : public OMR_InlinerPolicy * This query defines a group of methods that are small helpers in the java/lang/invoke package */ static bool isJSR292SmallHelperMethod(TR_ResolvedMethod *resolvedMethod); + + /** + * \brief + * This query answers whether the method is a simple non-native Unsafe method that contain a call to + * a native Unsafe method that would normally be handled in TR_J9InlinerPolicy::inlineUnsafeCall. If + * we can determine that the runtime checks in the wrapper method can be determined at compile time, + * it may be possible to treat the wrapper method as its underlying native Unsafe method and have it + * inlined in TR_J9InlinerPolicy::inlineUnsafeCall. + * + * \param + * resolvedMethod the TR_ResolvedMethod + * \return + * true if the method is a simple wrapper method for a native unsafe method, false otherwise + */ + static bool isSimpleWrapperForInlineableUnsafeNativeMethod(TR_ResolvedMethod *resolvedMethod); + }; class TR_J9JSR292InlinerPolicy : public TR_J9InlinerPolicy