diff --git a/runtime/compiler/codegen/J9RecognizedMethodsEnum.hpp b/runtime/compiler/codegen/J9RecognizedMethodsEnum.hpp index a508a6bb41d..0220c705f04 100644 --- a/runtime/compiler/codegen/J9RecognizedMethodsEnum.hpp +++ b/runtime/compiler/codegen/J9RecognizedMethodsEnum.hpp @@ -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, diff --git a/runtime/compiler/env/j9method.cpp b/runtime/compiler/env/j9method.cpp index 643d35b96d1..b034bb3f655 100644 --- a/runtime/compiler/env/j9method.cpp +++ b/runtime/compiler/env/j9method.cpp @@ -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} }; @@ -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; diff --git a/runtime/compiler/optimizer/InlinerTempForJ9.cpp b/runtime/compiler/optimizer/InlinerTempForJ9.cpp index 40bf5bf31d9..a948e4808a6 100644 --- a/runtime/compiler/optimizer/InlinerTempForJ9.cpp +++ b/runtime/compiler/optimizer/InlinerTempForJ9.cpp @@ -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()); @@ -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()); @@ -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 @@ -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: @@ -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: @@ -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; } @@ -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) { diff --git a/runtime/compiler/optimizer/J9Inliner.hpp b/runtime/compiler/optimizer/J9Inliner.hpp index e510766f3d4..918460d8ca1 100644 --- a/runtime/compiler/optimizer/J9Inliner.hpp +++ b/runtime/compiler/optimizer/J9Inliner.hpp @@ -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); @@ -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