Skip to content

Commit

Permalink
Recognize unsafe unaligned getters/setters
Browse files Browse the repository at this point in the history
The commits adds support for unaligned getter/setters in the
Unsafe class for the JIT.

Unaligned getters and setters are treated the same as their
aligned equivalents for ISAs which permit unaligned reads/stores.
This requires a change to the inliner to consider whether
to emit an unsafe store/read based on whether the target ISA permits
unaligned accesses. So far only the Z target does not permit unaligned
accesses, so the getters/setters will fall back to their Java
software implementation.

Signed-off-by: James You <[email protected]>
Also-by: Nazim Bhuiyan <[email protected]>
  • Loading branch information
jmesyou authored and nbhuiyan committed Nov 6, 2024
1 parent 24c86c0 commit 77b0f6f
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 5 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 @@ -3010,7 +3010,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 @@ -5632,6 +5640,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
47 changes: 45 additions & 2 deletions runtime/compiler/optimizer/InlinerTempForJ9.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1386,10 +1386,23 @@ 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;

// In general, Z does not permit unaligned accesses
if (isUnaligned && comp()->target().cpu.isZ())
return false;

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

Expand Down Expand Up @@ -1965,11 +1978,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()->target().cpu.isZ())
return false;

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

Expand Down Expand Up @@ -2063,6 +2086,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 +2097,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 +2603,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::Int8, /*needsNullCheck*/false, /*isUnaligned*/true);
case TR::jdk_internal_misc_Unsafe_getShortUnaligned:
return createUnsafeGetWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int16, /*needsNullCheck*/false, /*isUnaligned*/true);
case TR::jdk_internal_misc_Unsafe_getIntUnaligned:
return createUnsafeGetWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int32, /*needsNullCheck*/false, /*isUnaligned*/true);
case TR::jdk_internal_misc_Unsafe_getLongUnaligned:
return createUnsafeGetWithOffset(calleeSymbol, callerSymbol, callNodeTreeTop, callNode, TR::Int64, /*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
4 changes: 2 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

0 comments on commit 77b0f6f

Please sign in to comment.