From f5dcc80cd2febfb43de55b7342397acd04c22d0b Mon Sep 17 00:00:00 2001 From: midronij Date: Tue, 19 Sep 2023 09:46:04 -0400 Subject: [PATCH 1/2] Add API to query off heap allocation availability Add definitions for j9gc_off_heap_allocation_enabled and J9::ObjectModel::isOffHeapAllocationEnabled() Source: https://github.com/eclipse-openj9/openj9/pull/18163 Signed-off-by: midronij --- .../control/JITClientCompilationThread.cpp | 1 + runtime/compiler/env/J9ObjectModel.cpp | 12 ++++++++++++ runtime/compiler/env/J9ObjectModel.hpp | 1 + runtime/compiler/runtime/JITClientSession.hpp | 1 + runtime/gc/gctable.c | 1 + runtime/gc_base/gc_internal.h | 1 + runtime/gc_modron_startup/mmhelpers.cpp | 16 ++++++++++++++++ runtime/oti/j9nonbuilder.h | 1 + 8 files changed, 34 insertions(+) diff --git a/runtime/compiler/control/JITClientCompilationThread.cpp b/runtime/compiler/control/JITClientCompilationThread.cpp index 6fbe5d7459c..a78b7d7e92e 100644 --- a/runtime/compiler/control/JITClientCompilationThread.cpp +++ b/runtime/compiler/control/JITClientCompilationThread.cpp @@ -506,6 +506,7 @@ handleServerMessage(JITServer::ClientStream *client, TR_J9VM *fe, JITServer::Mes vmInfo._helperAddresses[i] = runtimeHelperValue((TR_RuntimeHelper) i); #endif vmInfo._isHotReferenceFieldRequired = TR::Compiler->om.isHotReferenceFieldRequired(); + vmInfo._isOffHeapAllocationEnabled = TR::Compiler->om.isOffHeapAllocationEnabled(); vmInfo._osrGlobalBufferSize = javaVM->osrGlobalBufferSize; vmInfo._needsMethodTrampolines = TR::CodeCacheManager::instance()->codeCacheConfig().needsMethodTrampolines(); vmInfo._objectAlignmentInBytes = TR::Compiler->om.objectAlignmentInBytes(); diff --git a/runtime/compiler/env/J9ObjectModel.cpp b/runtime/compiler/env/J9ObjectModel.cpp index a504557f5d3..7b7ccb3ec4c 100644 --- a/runtime/compiler/env/J9ObjectModel.cpp +++ b/runtime/compiler/env/J9ObjectModel.cpp @@ -222,6 +222,18 @@ J9::ObjectModel::isHotReferenceFieldRequired() return TR::Compiler->javaVM->memoryManagerFunctions->j9gc_hot_reference_field_required(TR::Compiler->javaVM); } +bool +J9::ObjectModel::isOffHeapAllocationEnabled() + { +#if defined(J9VM_OPT_JITSERVER) + if (auto stream = TR::CompilationInfo::getStream()) + { + auto *vmInfo = TR::compInfoPT->getClientData()->getOrCacheVMInfo(stream); + return vmInfo->_isOffHeapAllocationEnabled; + } +#endif /* defined(J9VM_OPT_JITSERVER) */ + return TR::Compiler->javaVM->memoryManagerFunctions->j9gc_off_heap_allocation_enabled(TR::Compiler->javaVM); + } UDATA J9::ObjectModel::elementSizeOfBooleanArray() diff --git a/runtime/compiler/env/J9ObjectModel.hpp b/runtime/compiler/env/J9ObjectModel.hpp index 0cb64836bc4..6b18549a783 100644 --- a/runtime/compiler/env/J9ObjectModel.hpp +++ b/runtime/compiler/env/J9ObjectModel.hpp @@ -86,6 +86,7 @@ class ObjectModel : public OMR::ObjectModelConnector int32_t sizeofReferenceField(); bool isHotReferenceFieldRequired(); + bool isOffHeapAllocationEnabled(); uintptr_t elementSizeOfBooleanArray(); uint32_t getSizeOfArrayElement(TR::Node *node); int64_t maxArraySizeInElementsForAllocation(TR::Node *newArray, TR::Compilation *comp); diff --git a/runtime/compiler/runtime/JITClientSession.hpp b/runtime/compiler/runtime/JITClientSession.hpp index 5cc4922a44f..8b8f62a6ffb 100644 --- a/runtime/compiler/runtime/JITClientSession.hpp +++ b/runtime/compiler/runtime/JITClientSession.hpp @@ -307,6 +307,7 @@ class ClientSessionData void *_helperAddresses[TR_numRuntimeHelpers]; #endif bool _isHotReferenceFieldRequired; + bool _isOffHeapAllocationEnabled; UDATA _osrGlobalBufferSize; bool _needsMethodTrampolines; int32_t _objectAlignmentInBytes; diff --git a/runtime/gc/gctable.c b/runtime/gc/gctable.c index 1ee5f62a067..c42aa2b1d0c 100644 --- a/runtime/gc/gctable.c +++ b/runtime/gc/gctable.c @@ -82,6 +82,7 @@ J9MemoryManagerFunctions MemoryManagerFunctions = { j9gc_concurrent_scavenger_enabled, j9gc_software_read_barrier_enabled, j9gc_hot_reference_field_required, + j9gc_off_heap_allocation_enabled, j9gc_max_hot_field_list_length, #if defined(J9VM_GC_HEAP_CARD_TABLE) j9gc_concurrent_getCardSize, diff --git a/runtime/gc_base/gc_internal.h b/runtime/gc_base/gc_internal.h index 0f0ef4bfc98..734475bc51c 100644 --- a/runtime/gc_base/gc_internal.h +++ b/runtime/gc_base/gc_internal.h @@ -98,6 +98,7 @@ extern J9_CFUNC UDATA j9gc_scavenger_enabled(J9JavaVM *javaVM); extern J9_CFUNC UDATA j9gc_concurrent_scavenger_enabled(J9JavaVM *javaVM); extern J9_CFUNC UDATA j9gc_software_read_barrier_enabled(J9JavaVM *javaVM); extern J9_CFUNC BOOLEAN j9gc_hot_reference_field_required(J9JavaVM *javaVM); +extern J9_CFUNC BOOLEAN j9gc_off_heap_allocation_enabled(J9JavaVM *javaVM); extern J9_CFUNC uint32_t j9gc_max_hot_field_list_length(J9JavaVM *javaVM); extern J9_CFUNC void j9gc_objaccess_indexableStoreAddress(J9VMThread *vmThread, J9IndexableObject *destObject, I_32 index, void *value, UDATA isVolatile); extern J9_CFUNC void j9gc_objaccess_mixedObjectStoreAddress(J9VMThread *vmThread, j9object_t destObject, UDATA offset, void *value, UDATA isVolatile); diff --git a/runtime/gc_modron_startup/mmhelpers.cpp b/runtime/gc_modron_startup/mmhelpers.cpp index 2dfa8f7c20b..12ac9c5e4f9 100644 --- a/runtime/gc_modron_startup/mmhelpers.cpp +++ b/runtime/gc_modron_startup/mmhelpers.cpp @@ -164,6 +164,22 @@ j9gc_hot_reference_field_required(J9JavaVM *javaVM) #endif /* defined(J9VM_GC_MODRON_SCAVENGER) || defined(OMR_GC_VLHGC) */ } +/** + * Query if off heap allocation for large objects is enabled. + * + * @param javaVM pointer to J9JavaVM + * @return true if extensions flag isVirtualLargeObjectHeapEnabled is set, 0 otherwise + */ +BOOLEAN +j9gc_off_heap_allocation_enabled(J9JavaVM *javaVM) +{ +#if defined(J9VM_GC_ENABLE_SPARSE_HEAP_ALLOCATION) + return MM_GCExtensions::getExtensions(javaVM)->isVirtualLargeObjectHeapEnabled; +#else /* defined(J9VM_GC_ENABLE_SPARSE_HEAP_ALLOCATION) */ + return FALSE; +#endif /* defined(J9VM_GC_ENABLE_SPARSE_HEAP_ALLOCATION) */ +} + /** * Query for the max hot field list length that a class is allowed to have. * Valid if dynamicBreadthFirstScanOrdering is enabled. diff --git a/runtime/oti/j9nonbuilder.h b/runtime/oti/j9nonbuilder.h index 523ecf401cf..b78f17b2767 100644 --- a/runtime/oti/j9nonbuilder.h +++ b/runtime/oti/j9nonbuilder.h @@ -4471,6 +4471,7 @@ typedef struct J9MemoryManagerFunctions { UDATA ( *j9gc_concurrent_scavenger_enabled)(struct J9JavaVM *javaVM) ; UDATA ( *j9gc_software_read_barrier_enabled)(struct J9JavaVM *javaVM) ; BOOLEAN ( *j9gc_hot_reference_field_required)(struct J9JavaVM *javaVM) ; + BOOLEAN ( *j9gc_off_heap_allocation_enabled)(struct J9JavaVM *javaVM) ; uint32_t ( *j9gc_max_hot_field_list_length)(struct J9JavaVM *javaVM) ; #if defined(J9VM_GC_HEAP_CARD_TABLE) UDATA ( *j9gc_concurrent_getCardSize)(struct J9JavaVM *javaVM) ; From e76675526bac40b6962133701dabbbfebaf82321 Mon Sep 17 00:00:00 2001 From: Shubham Verma Date: Sat, 5 Aug 2023 12:13:39 -0400 Subject: [PATCH 2/2] Add APIs to help with array access New APIs are: `generateDataAddrLoadTrees` `generateArrayAddressNode` `generateArrayStartTrees` `generateOffsetNode` Signed-off-by: Shubham Verma --- .../compiler/optimizer/J9TransformUtil.cpp | 93 +++++++++++++++++++ .../compiler/optimizer/J9TransformUtil.hpp | 86 ++++++++++++++++- 2 files changed, 178 insertions(+), 1 deletion(-) diff --git a/runtime/compiler/optimizer/J9TransformUtil.cpp b/runtime/compiler/optimizer/J9TransformUtil.cpp index a7c6abc1f2d..2a64a82f67d 100644 --- a/runtime/compiler/optimizer/J9TransformUtil.cpp +++ b/runtime/compiler/optimizer/J9TransformUtil.cpp @@ -90,6 +90,99 @@ J9::TransformUtil::generateArrayElementShiftAmountTrees( return shiftAmount; } +#if defined(J9VM_GC_ENABLE_SPARSE_HEAP_ALLOCATION) +TR::Node * +J9::TransformUtil::generateDataAddrLoadTrees(TR::Compilation *comp, TR::Node *arrayObject) + { + TR_ASSERT_FATAL_WITH_NODE(arrayObject, + TR::Compiler->om.isOffHeapAllocationEnabled(), + "This helper shouldn't be called if off heap allocation is disabled.\n"); + + TR::SymbolReference *dataAddrFieldOffset = comp->getSymRefTab()->findOrCreateContiguousArrayDataAddrFieldShadowSymRef(); + TR::Node *dataAddrField = TR::Node::createWithSymRef(TR::aloadi, 1, arrayObject, 0, dataAddrFieldOffset); + dataAddrField->setIsInternalPointer(true); + + return dataAddrField; + } +#endif /* J9VM_GC_ENABLE_SPARSE_HEAP_ALLOCATION */ + +TR::Node * +J9::TransformUtil::generateArrayAddressTrees(TR::Compilation *comp, TR::Node *arrayNode, TR::Node *offsetNode) + { + TR::Node *arrayAddressNode = NULL; + TR::Node *totalOffsetNode = NULL; + + TR_ASSERT_FATAL_WITH_NODE(arrayNode, + !TR::Compiler->om.canGenerateArraylets(), + "This helper shouldn't be called if arraylets are enabled.\n"); + +#if defined(J9VM_GC_ENABLE_SPARSE_HEAP_ALLOCATION) + if (TR::Compiler->om.isOffHeapAllocationEnabled()) + { + arrayAddressNode = generateDataAddrLoadTrees(comp, arrayNode); + if (offsetNode) + arrayAddressNode = TR::Node::create(TR::aladd, 2, arrayAddressNode, offsetNode); + } + else if (comp->target().is64Bit()) +#else + if (comp->target().is64Bit()) +#endif /* J9VM_GC_ENABLE_SPARSE_HEAP_ALLOCATION */ + { + totalOffsetNode = TR::Node::lconst(TR::Compiler->om.contiguousArrayHeaderSizeInBytes()); + if (offsetNode) + totalOffsetNode = TR::Node::create(TR::ladd, 2, offsetNode, totalOffsetNode); + arrayAddressNode = TR::Node::create(TR::aladd, 2, arrayNode, totalOffsetNode); + } + else + { + totalOffsetNode = TR::Node::iconst(TR::Compiler->om.contiguousArrayHeaderSizeInBytes()); + if (offsetNode) + totalOffsetNode = TR::Node::create(TR::iadd, 2, offsetNode, totalOffsetNode); + arrayAddressNode = TR::Node::create(TR::aiadd, 2, arrayNode, totalOffsetNode); + } + + return arrayAddressNode; + } + +TR::Node * +J9::TransformUtil::generateArrayStartTrees(TR::Compilation *comp, TR::Node *arrayObject) + { + TR::Node *firstArrayElementNode = generateArrayAddressTrees(comp, arrayObject); + return firstArrayElementNode; + } + +TR::Node * +J9::TransformUtil::generateArrayOffsetTrees(TR::Compilation *comp, TR::Node *indexNode, TR::Node *elementSizeNode, int32_t elementSize, bool useShiftOpCode) + { + TR::Node *offsetNode = indexNode->createLongIfNeeded(); + TR::Node *strideNode = elementSizeNode; + if (strideNode) + strideNode = strideNode->createLongIfNeeded(); + + if (strideNode != NULL || elementSize > 1) + { + TR::ILOpCodes offsetOpCode = TR::BadILOp; + if (comp->target().is64Bit()) + { + if (strideNode == NULL && elementSize > 1) + strideNode = TR::Node::lconst(indexNode, elementSize); + + offsetOpCode = useShiftOpCode ? TR::lshl : TR::lmul; + } + else + { + if (strideNode == NULL && elementSize > 1) + strideNode = TR::Node::iconst(indexNode, elementSize); + + offsetOpCode = useShiftOpCode ? TR::ishl : TR::imul; + } + + offsetNode = TR::Node::create(offsetOpCode, 2, offsetNode, strideNode); + } + + return offsetNode; + } + // // A few predicates describing shadow symbols that we can reason about at // compile time. Note that "final field" here doesn't rule out a pointer to a diff --git a/runtime/compiler/optimizer/J9TransformUtil.hpp b/runtime/compiler/optimizer/J9TransformUtil.hpp index b7a8e2a5d30..395c3875159 100644 --- a/runtime/compiler/optimizer/J9TransformUtil.hpp +++ b/runtime/compiler/optimizer/J9TransformUtil.hpp @@ -106,7 +106,91 @@ class OMR_EXTENSIBLE TransformUtil : public OMR::TransformUtilConnector TR::Compilation *comp, TR::Node *object); - static bool transformDirectLoad(TR::Compilation *, TR::Node *node); +#if defined(J9VM_GC_ENABLE_SPARSE_HEAP_ALLOCATION) + /** + * \brief + * Generate IL to load dataAddr pointer from the array header + * + * \param comp + * The compilation object + * + * \param arrayObject + * The array object node + * + * \return + * IL for loading dataAddr pointer + */ + static TR::Node *generateDataAddrLoadTrees(TR::Compilation *comp, TR::Node *arrayObject); +#endif /* J9VM_GC_ENABLE_SPARSE_HEAP_ALLOCATION */ + + /** + * \brief + * Generate array element access IL for on and off heap contiguous arrays + * + * \param comp + * The compilation object + * + * \param arrayNode + * The array object node + * + * \param offsetNode + * The offset node (in bytes) + * + * \return + * IL to access array element at offset provided by offsetNode or + * first array element if no offset node is provided + */ + static TR::Node *generateArrayAddressTrees( + TR::Compilation *comp, + TR::Node *arrayNode, + TR::Node *offsetNode = NULL); + + /** + * \brief + * Generate IL to access first array element + * + * \param comp + * The compilation object + * + * \param arrayObject + * The array object node + * + * \return + * IL for accessing first array element + */ + static TR::Node *generateArrayStartTrees(TR::Compilation *comp, TR::Node *arrayObject); + + /** + * \brief + * Generates IL to convert element index to offset in bytes using element + * size (node or integer) + * + * \param comp + * The compilation object + * + * \param indexNode + * Array element index node + * + * \param elementSizeNode + * Array element size tree (ex: const node containing element size) + * + * \param elementSize + * Array element size + * + * \param useShiftOpCode + * Use left shift instead of multiplication + * + * \return + * IL to convert array element index to offset in bytes + */ + static TR::Node *generateArrayOffsetTrees( + TR::Compilation *comp, + TR::Node *indexNode, + TR::Node *elementSizeNode = NULL, + int32_t elementSize = 0, + bool useShiftOpCode = false); + + static bool transformDirectLoad(TR::Compilation *comp, TR::Node *node); /** * \brief