Skip to content

Commit

Permalink
Merge pull request #19668 from nbhuiyan/unaligned-getput
Browse files Browse the repository at this point in the history
Recognize unsafe unaligned getters/setters
  • Loading branch information
jdmpapin authored Nov 13, 2024
2 parents ab5676f + ffdfec6 commit 4b8e6ef
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 6 deletions.
8 changes: 8 additions & 0 deletions runtime/compiler/codegen/J9RecognizedMethodsEnum.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,14 @@
jdk_internal_misc_Unsafe_compareAndExchangeReference,

jdk_internal_misc_Unsafe_copyMemory0,
jdk_internal_misc_Unsafe_getCharUnaligned,
jdk_internal_misc_Unsafe_getShortUnaligned,
jdk_internal_misc_Unsafe_getIntUnaligned,
jdk_internal_misc_Unsafe_getLongUnaligned,
jdk_internal_misc_Unsafe_putCharUnaligned,
jdk_internal_misc_Unsafe_putShortUnaligned,
jdk_internal_misc_Unsafe_putIntUnaligned,
jdk_internal_misc_Unsafe_putLongUnaligned,
jdk_internal_loader_NativeLibraries_load,
jdk_internal_util_ArraysSupport_vectorizedMismatch,
jdk_internal_util_ArraysSupport_vectorizedHashCode,
Expand Down
18 changes: 17 additions & 1 deletion runtime/compiler/env/j9method.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3034,7 +3034,15 @@ void TR_ResolvedJ9Method::construct()
{x(TR::sun_misc_Unsafe_ensureClassInitialized, "ensureClassInitialized", "(Ljava/lang/Class;)V")},
{x(TR::sun_misc_Unsafe_allocateInstance, "allocateInstance", "(Ljava/lang/Class;)Ljava/lang/Object;")},
{x(TR::sun_misc_Unsafe_allocateUninitializedArray0, "allocateUninitializedArray0", "(Ljava/lang/Class;I)Ljava/lang/Object;")},
{x(TR::jdk_internal_misc_Unsafe_copyMemory0, "copyMemory0", "(Ljava/lang/Object;JLjava/lang/Object;JJ)V")},
{x(TR::jdk_internal_misc_Unsafe_copyMemory0, "copyMemory0", "(Ljava/lang/Object;JLjava/lang/Object;JJ)V")},
{x(TR::jdk_internal_misc_Unsafe_getCharUnaligned, "getCharUnaligned", "(Ljava/lang/Object;J)C")},
{x(TR::jdk_internal_misc_Unsafe_getShortUnaligned, "getShortUnaligned", "(Ljava/lang/Object;J)S")},
{x(TR::jdk_internal_misc_Unsafe_getIntUnaligned, "getIntUnaligned", "(Ljava/lang/Object;J)I")},
{x(TR::jdk_internal_misc_Unsafe_getLongUnaligned, "getLongUnaligned", "(Ljava/lang/Object;J)J")},
{x(TR::jdk_internal_misc_Unsafe_putCharUnaligned, "putCharUnaligned", "(Ljava/lang/Object;JC)V")},
{x(TR::jdk_internal_misc_Unsafe_putShortUnaligned, "putShortUnaligned", "(Ljava/lang/Object;JS)V")},
{x(TR::jdk_internal_misc_Unsafe_putIntUnaligned, "putIntUnaligned", "(Ljava/lang/Object;JI)V")},
{x(TR::jdk_internal_misc_Unsafe_putLongUnaligned, "putLongUnaligned", "(Ljava/lang/Object;JJ)V")},
{ TR::unknownMethod}
};

Expand Down Expand Up @@ -5656,6 +5664,14 @@ TR_J9MethodBase::isUnsafeWithObjectArg()
case TR::sun_misc_Unsafe_putFloatOrdered_jlObjectJF_V:
case TR::sun_misc_Unsafe_putDoubleOrdered_jlObjectJD_V:
case TR::sun_misc_Unsafe_putObjectOrdered_jlObjectJjlObject_V:
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:
return false;
Expand Down
74 changes: 71 additions & 3 deletions runtime/compiler/optimizer/InlinerTempForJ9.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1386,10 +1386,22 @@ Unsafe.getShort.
*/

bool
TR_J9InlinerPolicy::createUnsafePutWithOffset(TR::ResolvedMethodSymbol *calleeSymbol, TR::ResolvedMethodSymbol *callerSymbol, TR::TreeTop * callNodeTreeTop, TR::Node * unsafeCall, TR::DataType type, bool isVolatile, bool needNullCheck, bool isOrdered)
TR_J9InlinerPolicy::createUnsafePutWithOffset(TR::ResolvedMethodSymbol *calleeSymbol,
TR::ResolvedMethodSymbol *callerSymbol,
TR::TreeTop * callNodeTreeTop,
TR::Node * unsafeCall,
TR::DataType type,
bool isVolatile,
bool needNullCheck,
bool isOrdered,
bool isUnaligned)
{
if (isVolatile && type == TR::Int64 && comp()->target().is32Bit() && !comp()->cg()->getSupportsInlinedAtomicLongVolatiles())
return false;

if (isUnaligned && comp()->cg()->getSupportsAlignedAccessOnly())
return false;

if (debug("traceUnsafe"))
printf("createUnsafePutWithOffset %d in %s\n", type.getDataType(), comp()->signature());

Expand Down Expand Up @@ -1965,11 +1977,21 @@ TR_J9InlinerPolicy::createUnsafeCASCallDiamond(TR::TreeTop *callNodeTreeTop, TR:


bool
TR_J9InlinerPolicy::createUnsafeGetWithOffset(TR::ResolvedMethodSymbol *calleeSymbol, TR::ResolvedMethodSymbol *callerSymbol, TR::TreeTop * callNodeTreeTop, TR::Node * unsafeCall, TR::DataType type, bool isVolatile, bool needNullCheck)
TR_J9InlinerPolicy::createUnsafeGetWithOffset(TR::ResolvedMethodSymbol *calleeSymbol,
TR::ResolvedMethodSymbol *callerSymbol,
TR::TreeTop * callNodeTreeTop,
TR::Node * unsafeCall,
TR::DataType type,
bool isVolatile,
bool needNullCheck,
bool isUnaligned)
{
if (isVolatile && type == TR::Int64 && comp()->target().is32Bit() && !comp()->cg()->getSupportsInlinedAtomicLongVolatiles())
return false;

if (isUnaligned && comp()->cg()->getSupportsAlignedAccessOnly())
return false;

if (debug("traceUnsafe"))
printf("createUnsafeGetWithOffset %s in %s\n", type.toString(), comp()->signature());

Expand Down Expand Up @@ -2063,6 +2085,7 @@ TR_J9InlinerPolicy::createUnsafeGetWithOffset(TR::ResolvedMethodSymbol *calleeSy
case TR::sun_misc_Unsafe_getChar_jlObjectJ_C:
case TR::sun_misc_Unsafe_getCharVolatile_jlObjectJ_C:
case TR::sun_misc_Unsafe_getChar_J_C:
case TR::jdk_internal_misc_Unsafe_getCharUnaligned:
unsignedType = true;
break;
//byte and short are signed so we need a signed conversion
Expand All @@ -2073,6 +2096,7 @@ TR_J9InlinerPolicy::createUnsafeGetWithOffset(TR::ResolvedMethodSymbol *calleeSy
case TR::sun_misc_Unsafe_getShort_jlObjectJ_S:
case TR::sun_misc_Unsafe_getShortVolatile_jlObjectJ_S:
case TR::sun_misc_Unsafe_getShort_J_S:
case TR::jdk_internal_misc_Unsafe_getShortUnaligned:
unsignedType = false;
break;
default:
Expand Down Expand Up @@ -2578,6 +2602,24 @@ TR_J9InlinerPolicy::inlineUnsafeCall(TR::ResolvedMethodSymbol *calleeSymbol, TR:
case TR::sun_misc_Unsafe_putObjectOrdered_jlObjectJjlObject_V:
return createUnsafePutWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Address, false, true, true);

// 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::Int16, /*isVolatile*/false, /*needsNullCheck*/false, /*isUnaligned*/true);
case TR::jdk_internal_misc_Unsafe_getShortUnaligned:
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, /*isVolatile*/false, /*needsNullCheck*/false, /*isUnaligned*/true);
case TR::jdk_internal_misc_Unsafe_getLongUnaligned:
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:
return createUnsafePutWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int16, /*isVolatile*/false, /*needsNullCheck*/false, /*isOrdered*/false, /*isUnaligned*/true);
case TR::jdk_internal_misc_Unsafe_putIntUnaligned:
return createUnsafePutWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int32, /*isVolatile*/false, /*needsNullCheck*/false, /*isOrdered*/false, /*isUnaligned*/true);
case TR::jdk_internal_misc_Unsafe_putLongUnaligned:
return createUnsafePutWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int64, /*isVolatile*/false, /*needsNullCheck*/false, /*isOrdered*/false, /*isUnaligned*/true);

case TR::sun_misc_Unsafe_getBooleanVolatile_jlObjectJ_Z:
return createUnsafeGetWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int8, true);
case TR::sun_misc_Unsafe_getByteVolatile_jlObjectJ_B:
Expand Down Expand Up @@ -2743,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 @@ -5998,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
20 changes: 18 additions & 2 deletions runtime/compiler/optimizer/J9Inliner.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -230,13 +230,13 @@ class TR_J9InlinerPolicy : public OMR_InlinerPolicy
* after executing either \c branchTargetTree or \c fallThroughTree
*/
TR::Block * createUnsafeGetPutCallDiamond(TR::TreeTop* callNodeTreeTop, TR::TreeTop* comparisonTree, TR::TreeTop* branchTargetTree, TR::TreeTop* fallThroughTree);
bool createUnsafePutWithOffset(TR::ResolvedMethodSymbol *, TR::ResolvedMethodSymbol *, TR::TreeTop *, TR::Node *, TR::DataType, bool, bool needNullCheck = false, bool isOrdered = false);
bool createUnsafePutWithOffset(TR::ResolvedMethodSymbol *, TR::ResolvedMethodSymbol *, TR::TreeTop *, TR::Node *, TR::DataType, bool, bool needNullCheck = false, bool isOrdered = false, bool isUnaligned = false);
TR::TreeTop* genDirectAccessCodeForUnsafeGetPut(TR::Node* callNode, bool conversionNeeded, bool isUnsafeGet);
void createTempsForUnsafePutGet(TR::Node*& unsafeAddress, TR::Node* unsafeCall, TR::TreeTop* callNodeTreeTop, TR::Node*& offset, TR::SymbolReference*& newSymbolReferenceForAddress, bool isUnsafeGet);
bool createUnsafeGet(TR::ResolvedMethodSymbol *, TR::ResolvedMethodSymbol *, TR::TreeTop *, TR::Node *, TR::DataType, bool compress = true);
bool createUnsafePut(TR::ResolvedMethodSymbol *, TR::ResolvedMethodSymbol *, TR::TreeTop *, TR::Node *, TR::DataType, bool compress = true);
TR::Node * createUnsafeAddress(TR::Node *);
bool createUnsafeGetWithOffset(TR::ResolvedMethodSymbol *, TR::ResolvedMethodSymbol *, TR::TreeTop *, TR::Node *, TR::DataType, bool, bool needNullCheck = false);
bool createUnsafeGetWithOffset(TR::ResolvedMethodSymbol *, TR::ResolvedMethodSymbol *, TR::TreeTop *, TR::Node *, TR::DataType, bool, bool needNullCheck = false, bool isUnaligned = false);
TR::Node * createUnsafeAddressWithOffset(TR::Node *);
bool createUnsafeFence(TR::TreeTop *, TR::Node *, TR::ILOpCodes);

Expand Down 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 4b8e6ef

Please sign in to comment.