Skip to content

Commit

Permalink
Enable inlining of non-native Unsafe unaligned getters and setters
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
nbhuiyan committed Nov 6, 2024
1 parent 77b0f6f commit ffdfec6
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 8 deletions.
41 changes: 33 additions & 8 deletions runtime/compiler/optimizer/InlinerTempForJ9.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"))
Expand Down Expand Up @@ -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"))
Expand Down Expand Up @@ -2605,13 +2604,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::Int16, /*isVolatile*/false, /*needsNullCheck*/false, /*isOrdered*/false, /*isUnaligned*/true);
case TR::jdk_internal_misc_Unsafe_putShortUnaligned:
Expand Down Expand Up @@ -2786,8 +2785,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;
}
Expand Down Expand Up @@ -6041,6 +6044,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)
{
Expand Down
16 changes: 16 additions & 0 deletions runtime/compiler/optimizer/J9Inliner.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,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
Expand Down

0 comments on commit ffdfec6

Please sign in to comment.