From 4f814822cdaf6bd4a657892e05f40f95dfd14c7d Mon Sep 17 00:00:00 2001 From: Frank Kang Date: Wed, 23 Aug 2023 12:45:12 -0700 Subject: [PATCH] GC division by 0 fix for 0-stride flattened array Update gc code to support 0-stride flattened array and get rid of division by 0 exceptions This is done by adding manually comparison against 0, might find better alternatives in the future. Related: #14027 Signed-off-by: Frank Kang --- runtime/gc_base/IndexableObjectAllocationModel.cpp | 8 +++++++- runtime/gc_glue_java/ArrayletObjectModel.cpp | 2 +- runtime/gc_glue_java/ArrayletObjectModel.hpp | 8 +++++++- runtime/gc_include/ObjectAllocationAPI.hpp | 5 +++-- runtime/gc_structs/FlattenedContiguousArrayIterator.hpp | 3 +++ 5 files changed, 21 insertions(+), 5 deletions(-) diff --git a/runtime/gc_base/IndexableObjectAllocationModel.cpp b/runtime/gc_base/IndexableObjectAllocationModel.cpp index c424f1773a4..b08965b84ef 100644 --- a/runtime/gc_base/IndexableObjectAllocationModel.cpp +++ b/runtime/gc_base/IndexableObjectAllocationModel.cpp @@ -145,7 +145,13 @@ MM_IndexableObjectAllocationModel::initializeIndexableObject(MM_EnvironmentBase /* Lay out arraylet and arrayoid pointers */ switch (_layout) { case GC_ArrayletObjectModel::InlineContiguous: - Assert_MM_true(1 == _numberOfArraylets); + /** + * _numberOfArraylets is set to 0 for 0-stride flattened array, and we + * can recognize this case by checking if _dataSize is 0. + * Note there are two cases that _dataSize is 0: 0-stride flattened array or 0-length array + * But the latter is treated as discontiguous and not following this path + */ + Assert_MM_true((0 == _dataSize) || (1 == _numberOfArraylets)); break; case GC_ArrayletObjectModel::Discontiguous: diff --git a/runtime/gc_glue_java/ArrayletObjectModel.cpp b/runtime/gc_glue_java/ArrayletObjectModel.cpp index 538691c2a83..37ac858cff1 100644 --- a/runtime/gc_glue_java/ArrayletObjectModel.cpp +++ b/runtime/gc_glue_java/ArrayletObjectModel.cpp @@ -94,7 +94,7 @@ GC_ArrayletObjectModel::getArrayletLayout(J9Class* clazz, UDATA dataSizeInBytes, /* CMVC 135307 : when checking for InlineContiguous layout, perform subtraction as adding to dataSizeInBytes could trigger overflow. */ if ((largestDesirableSpine == UDATA_MAX) || (dataSizeInBytes <= (largestDesirableSpine - minimumSpineSizeAfterGrowing - contiguousIndexableHeaderSize()))) { layout = InlineContiguous; - if(0 == dataSizeInBytes) { + if ((0 == dataSizeInBytes) && (0 < J9ARRAYCLASS_GET_STRIDE(clazz))) { /* Zero sized NUA uses the discontiguous shape */ layout = Discontiguous; } diff --git a/runtime/gc_glue_java/ArrayletObjectModel.hpp b/runtime/gc_glue_java/ArrayletObjectModel.hpp index 27a16bf0920..21c922ac9e0 100644 --- a/runtime/gc_glue_java/ArrayletObjectModel.hpp +++ b/runtime/gc_glue_java/ArrayletObjectModel.hpp @@ -366,7 +366,7 @@ class GC_ArrayletObjectModel : public GC_ArrayletObjectModelBase uintptr_t stride = J9ARRAYCLASS_GET_STRIDE(clazzPtr); uintptr_t size = numberOfElements * stride; uintptr_t alignedSize = UDATA_MAX; - if ((size / stride) == numberOfElements) { + if ((0 == stride) || ((size / stride) == numberOfElements)) { alignedSize = MM_Math::roundToSizeofUDATA(size); if (alignedSize < size) { alignedSize = UDATA_MAX; @@ -478,6 +478,9 @@ class GC_ArrayletObjectModel : public GC_ArrayletObjectModelBase void* srcData = getDataPointerForContiguous(srcObject); switch(elementSize) { + case 0: + break; + case 1: // byte/boolean { @@ -637,6 +640,9 @@ class GC_ArrayletObjectModel : public GC_ArrayletObjectModelBase void* destData = getDataPointerForContiguous(destObject); switch(elementSize) { + case 0: + break; + case 1: // byte/boolean { diff --git a/runtime/gc_include/ObjectAllocationAPI.hpp b/runtime/gc_include/ObjectAllocationAPI.hpp index fe5a9062abd..e46e601421d 100644 --- a/runtime/gc_include/ObjectAllocationAPI.hpp +++ b/runtime/gc_include/ObjectAllocationAPI.hpp @@ -447,10 +447,11 @@ class MM_ObjectAllocationAPI VMINLINE j9object_t inlineAllocateIndexableValueTypeObject(J9VMThread *currentThread, J9Class *arrayClass, uint32_t size, bool initializeSlots = true, bool memoryBarrier = true, bool sizeCheck = true) { - uintptr_t dataSize = ((uintptr_t)size) * J9ARRAYCLASS_GET_STRIDE(arrayClass); + uintptr_t stride = J9ARRAYCLASS_GET_STRIDE(arrayClass); + uintptr_t dataSize = ((uintptr_t)size) * stride; bool validSize = true; #if !defined(J9VM_ENV_DATA64) - validSize = !sizeCheck || (size < ((uint32_t)J9_MAXIMUM_INDEXABLE_DATA_SIZE / J9ARRAYCLASS_GET_STRIDE(arrayClass))); + validSize = (!sizeCheck) || (0 == stride) || (size < ((uint32_t)J9_MAXIMUM_INDEXABLE_DATA_SIZE / stride)); #endif /* J9VM_ENV_DATA64 */ return inlineAllocateIndexableObjectImpl(currentThread, arrayClass, size, dataSize, validSize, initializeSlots, memoryBarrier); } diff --git a/runtime/gc_structs/FlattenedContiguousArrayIterator.hpp b/runtime/gc_structs/FlattenedContiguousArrayIterator.hpp index 61c71115772..eaba1bcbd55 100644 --- a/runtime/gc_structs/FlattenedContiguousArrayIterator.hpp +++ b/runtime/gc_structs/FlattenedContiguousArrayIterator.hpp @@ -91,6 +91,9 @@ class GC_FlattenedContiguousArrayIterator */ MMINLINE UDATA getIndex() { + if (0 == _elementStride) { + return 0; + } return ((uintptr_t)_scanPtr - (uintptr_t)_basePtr) / _elementStride; }