8080//
8181static bool isVarHandleOperationMethod (TR ::RecognizedMethod rm)
8282{
83- return TR_J9MethodBase::isVarHandleOperationMethod (rm)
84- && rm != TR ::java_lang_invoke_VarHandleByteArrayAsX_ByteBufferHandle_method;
83+ if (rm == TR ::java_lang_invoke_VarHandleByteArrayAsX_ByteBufferHandle_method)
84+ return false ;
85+
86+ #if defined(J9VM_OPT_OPENJDK_METHODHANDLE)
87+ // The memory segment view operation methods perform the access on a base that is
88+ // either null (NativeMemorySegmentImpl, raw native address) or a primitive array
89+ // (HeapMemorySegmentImpl). Both shapes can be lowered to the same aladd(base, offset)
90+ // load/store only while arrays are contiguous and on-heap, so give up when arraylets
91+ // or off-heap allocation are possible.
92+ if (rm == TR ::java_lang_invoke_VarHandleSegmentAsX_method) {
93+ if (TR ::Compiler->om .canGenerateArraylets ())
94+ return false ;
95+ #if defined(J9VM_GC_SPARSE_HEAP_ALLOCATION)
96+ if (TR ::Compiler->om .isOffHeapAllocationEnabled ())
97+ return false ;
98+ #endif /* J9VM_GC_SPARSE_HEAP_ALLOCATION */
99+ }
100+ #endif /* J9VM_OPT_OPENJDK_METHODHANDLE */
101+
102+ return TR_J9MethodBase::isVarHandleOperationMethod (rm);
85103}
86104
87105static TR ::RecognizedMethod getVarHandleAccessMethodFromInlinedCallStack (TR ::Compilation *comp, TR ::Node *node)
@@ -182,6 +200,7 @@ static bool isVarHandleOperationMethodOnArray(TR::RecognizedMethod rm)
182200
183201 case TR ::java_lang_invoke_VarHandleX_Array_method:
184202 case TR ::java_lang_invoke_VarHandleByteArrayAsX_ArrayHandle_method:
203+ case TR ::java_lang_invoke_VarHandleSegmentAsX_method:
185204#else
186205 case TR ::java_lang_invoke_ArrayVarHandle_ArrayVarHandleOperations_OpMethod:
187206 case TR ::java_lang_invoke_ByteArrayViewVarHandle_ByteArrayViewVarHandleOperations_OpMethod:
@@ -370,6 +389,63 @@ bool TR_UnsafeFastPath::tryTransformUnsafeAtomicCallInVarHandleAccessMethod(TR::
370389 return true ;
371390}
372391
392+ // The Unsafe.getXUnaligned(Object, long) / putXUnaligned(Object, long, X) wrappers are
393+ // plain Java methods whose bodies re-assemble the value byte- or short-wise when the
394+ // offset may be misaligned. On targets that support misaligned accesses they can be
395+ // lowered to a single load/store just like the corresponding aligned natives, but they
396+ // are not part of isUnsafeGetPutWithObjectArg(), so they get their own helpers here.
397+ static bool isUnalignedUnsafeGetPut (TR ::RecognizedMethod rm)
398+ {
399+ switch (rm) {
400+ case TR ::jdk_internal_misc_Unsafe_getCharUnaligned:
401+ case TR ::jdk_internal_misc_Unsafe_getShortUnaligned:
402+ case TR ::jdk_internal_misc_Unsafe_getIntUnaligned:
403+ case TR ::jdk_internal_misc_Unsafe_getLongUnaligned:
404+ case TR ::jdk_internal_misc_Unsafe_putCharUnaligned:
405+ case TR ::jdk_internal_misc_Unsafe_putShortUnaligned:
406+ case TR ::jdk_internal_misc_Unsafe_putIntUnaligned:
407+ case TR ::jdk_internal_misc_Unsafe_putLongUnaligned:
408+ return true ;
409+ default :
410+ return false ;
411+ }
412+ return false ;
413+ }
414+
415+ static bool isUnalignedUnsafePut (TR ::RecognizedMethod rm)
416+ {
417+ switch (rm) {
418+ case TR ::jdk_internal_misc_Unsafe_putCharUnaligned:
419+ case TR ::jdk_internal_misc_Unsafe_putShortUnaligned:
420+ case TR ::jdk_internal_misc_Unsafe_putIntUnaligned:
421+ case TR ::jdk_internal_misc_Unsafe_putLongUnaligned:
422+ return true ;
423+ default :
424+ return false ;
425+ }
426+ return false ;
427+ }
428+
429+ static TR ::DataType dataTypeForUnalignedUnsafeGetPut (TR ::RecognizedMethod rm)
430+ {
431+ switch (rm) {
432+ case TR ::jdk_internal_misc_Unsafe_getCharUnaligned:
433+ case TR ::jdk_internal_misc_Unsafe_getShortUnaligned:
434+ case TR ::jdk_internal_misc_Unsafe_putCharUnaligned:
435+ case TR ::jdk_internal_misc_Unsafe_putShortUnaligned:
436+ return TR ::Int16;
437+ case TR ::jdk_internal_misc_Unsafe_getIntUnaligned:
438+ case TR ::jdk_internal_misc_Unsafe_putIntUnaligned:
439+ return TR ::Int32;
440+ case TR ::jdk_internal_misc_Unsafe_getLongUnaligned:
441+ case TR ::jdk_internal_misc_Unsafe_putLongUnaligned:
442+ return TR ::Int64;
443+ default :
444+ TR_ASSERT (false , " Method is not an unaligned unsafe get/put\n " );
445+ }
446+ return TR ::NoType;
447+ }
448+
373449static bool needUnsignedConversion (TR ::RecognizedMethod methodToReduce)
374450{
375451 switch (methodToReduce) {
@@ -378,6 +454,7 @@ static bool needUnsignedConversion(TR::RecognizedMethod methodToReduce)
378454 case TR ::com_ibm_jit_JITHelpers_getCharFromArrayVolatile:
379455 case TR ::java_lang_StringUTF16_getChar:
380456 case TR ::java_lang_StringUTF16_putChar:
457+ case TR ::jdk_internal_misc_Unsafe_getCharUnaligned:
381458 return true ;
382459
383460 default :
@@ -751,18 +828,27 @@ int32_t TR_UnsafeFastPath::perform()
751828 if (recognizedVarHandleOpMethod != TR ::unknownMethod)
752829 callerMethod = recognizedVarHandleOpMethod;
753830 TR ::RecognizedMethod calleeMethod = symbol->getRecognizedMethod ();
754- if (isKnownUnsafeCaller (callerMethod) && TR_J9MethodBase::isUnsafeGetPutWithObjectArg (calleeMethod)) {
831+ // The single load/store an unaligned wrapper reduces to uses the packed element
832+ // shape, so only callers known to access packed elements (byte array views and
833+ // memory segments) qualify, and only on targets that allow misaligned accesses.
834+ bool isKnownCaller = isKnownUnsafeCaller (callerMethod);
835+ bool isUnalignedCallee = isKnownCaller && isUnalignedUnsafeGetPut (calleeMethod)
836+ && !comp ()->cg ()->getSupportsAlignedAccessOnly () && isUnsafeCallerAccessingArrayElement (callerMethod);
837+ if (isKnownCaller
838+ && (TR_J9MethodBase::isUnsafeGetPutWithObjectArg (calleeMethod) || isUnalignedCallee)) {
755839 if (isUnsafeCallerAccessingStaticField (callerMethod))
756840 isStatic = true ;
757841 if (isUnsafeCallerAccessingArrayElement (callerMethod))
758842 isArrayOperation = true ;
759843
760- if (isArrayOperation)
844+ if (isUnalignedCallee)
845+ type = dataTypeForUnalignedUnsafeGetPut (calleeMethod);
846+ else if (isArrayOperation)
761847 type = TR_J9MethodBase::unsafeDataTypeForArray (calleeMethod);
762848 else
763849 type = TR_J9MethodBase::unsafeDataTypeForObject (calleeMethod);
764850
765- if (TR_J9MethodBase::isUnsafePut (calleeMethod))
851+ if (TR_J9MethodBase::isUnsafePut (calleeMethod) || isUnalignedUnsafePut (calleeMethod) )
766852 value = node->getChild (3 );
767853
768854 if (TR_J9MethodBase::isVolatileUnsafe (calleeMethod))
@@ -813,7 +899,16 @@ int32_t TR_UnsafeFastPath::perform()
813899 }
814900
815901 object = node->getChild (objectChild);
902+ #if defined(J9VM_OPT_OPENJDK_METHODHANDLE)
903+ // A MemorySegment access base is null for native segments, so it must not
904+ // be marked non-null. The address computation below is correct either way:
905+ // null base + absolute offset, or array base (non-null) + element offset.
906+ if (callerMethod != TR ::java_lang_invoke_VarHandleSegmentAsX_method) {
907+ object->setIsNonNull (true );
908+ }
909+ #else /* J9VM_OPT_OPENJDK_METHODHANDLE */
816910 object->setIsNonNull (true );
911+ #endif /* J9VM_OPT_OPENJDK_METHODHANDLE */
817912 if (isStatic) {
818913 TR ::Node *jlClass = object;
819914 TR ::Node *j9Class = TR::Node::createWithSymRef (TR ::aloadi, 1 , 1 , jlClass,
0 commit comments