From 131768462c4271461ddd46988a9231ca262f6e26 Mon Sep 17 00:00:00 2001 From: Tobi Ajila Date: Mon, 2 Dec 2019 12:33:18 -0500 Subject: [PATCH] Add structral comparison barriers In #7743 a flag (J9ClassCanSupportFastSubstitutability) is added to each valueType class if it does not contain any floating point primitives or references that might potentially contain an unflattened valuetype or a flattened valuetype that does not contain J9ClassCanSupportFastSubstitutability. For these classes a structural comparison can be performed. This is essentially performing a memory comparison over the length of the instances, if they are equivalent the result is true, otherwise false. Since it will only contain scalar primitives and (non value) references, equality can be determined by simply performing a memory comparison. Unlike with floating point types or non-flattened valuetypes where determining equality is more complicated. A barrier helper is required as these instances may contain references. In modes where no read barriers are required memcmp can be used. Signed-off-by: Tobi Ajila --- runtime/gc/gctable.c | 1 + runtime/gc_base/ObjectAccessBarrier.cpp | 54 ++++++++++++++++++- runtime/gc_base/ObjectAccessBarrier.hpp | 1 + runtime/gc_base/accessBarrier.cpp | 10 ++++ runtime/gc_base/gc_internal.h | 1 + runtime/gc_include/ObjectAccessBarrierAPI.hpp | 17 ++++++ runtime/oti/j9nonbuilder.h | 1 + runtime/vm/BytecodeInterpreter.hpp | 8 +-- 8 files changed, 88 insertions(+), 5 deletions(-) diff --git a/runtime/gc/gctable.c b/runtime/gc/gctable.c index 180513e58f2..726b04cf070 100644 --- a/runtime/gc/gctable.c +++ b/runtime/gc/gctable.c @@ -179,6 +179,7 @@ J9MemoryManagerFunctions MemoryManagerFunctions = { j9gc_objaccess_copyObjectFields, j9gc_objaccess_copyObjectFieldsToFlattenedArrayElement, j9gc_objaccess_copyObjectFieldsFromFlattenedArrayElement, + j9gc_objaccess_structuralCompareFlattenedObjects, j9gc_objaccess_cloneIndexableObject, j9gc_objaccess_asConstantPoolObject, #if defined(J9VM_GC_REALTIME) diff --git a/runtime/gc_base/ObjectAccessBarrier.cpp b/runtime/gc_base/ObjectAccessBarrier.cpp index 378bcf7b9c3..1272515f93b 100644 --- a/runtime/gc_base/ObjectAccessBarrier.cpp +++ b/runtime/gc_base/ObjectAccessBarrier.cpp @@ -1377,6 +1377,58 @@ MM_ObjectAccessBarrier::cloneObject(J9VMThread *vmThread, J9Object *srcObject, J copyObjectFields(vmThread, J9GC_J9OBJECT_CLAZZ_THREAD(srcObject, vmThread), srcObject, objectHeaderSize, destObject, objectHeaderSize); } +BOOLEAN +MM_ObjectAccessBarrier::structuralCompareFlattenedObjects(J9VMThread *vmThread, J9Class *valueClass, j9object_t lhsObject, j9object_t rhsObject, UDATA startOffset) +{ + bool result = true; + const UDATA *descriptionPtr = (UDATA *) valueClass->instanceDescription; + UDATA descriptionBits = 0; + + Assert_MM_true(J9_IS_J9CLASS_VALUETYPE(valueClass)); + + if(((UDATA)descriptionPtr) & 1) { + descriptionBits = ((UDATA)descriptionPtr) >> 1; + } else { + descriptionBits = *descriptionPtr++; + } + + UDATA descriptionIndex = J9_OBJECT_DESCRIPTION_SIZE - 1; + UDATA offset = 0; + UDATA limit = valueClass->totalInstanceSize; + + U_32 firstFieldOffset = (U_32) valueClass->backfillOffset; + if (0 != firstFieldOffset) { + /* subtract padding */ + offset += firstFieldOffset; + descriptionBits >>= 1; + descriptionIndex -= 1; + } + + while (offset < limit) { + /* Determine if the slot contains an object pointer or not */ + if(descriptionBits & 1) { + if (mixedObjectReadObject(vmThread, lhsObject, startOffset + offset, false) != mixedObjectReadObject(vmThread, rhsObject, startOffset + offset, false)) { + result = false; + break; + } + + } else { + if (*(fj9object_t *)((UDATA)lhsObject + startOffset + offset) != *(fj9object_t *)((UDATA)rhsObject + startOffset + offset)) { + result = false; + break; + } + } + descriptionBits >>= 1; + if(descriptionIndex-- == 0) { + descriptionBits = *descriptionPtr++; + descriptionIndex = J9_OBJECT_DESCRIPTION_SIZE - 1; + } + offset += sizeof(fj9object_t); + } + + return result; +} + /** * Copy all of the fields of a value class instance to another value class instance. * The source or destination may be a flattened value within another object, meaning @@ -1415,7 +1467,7 @@ MM_ObjectAccessBarrier::copyObjectFields(J9VMThread *vmThread, J9Class *objectCl } const UDATA *descriptionPtr = (UDATA *) objectClass->instanceDescription; - UDATA descriptionBits; + UDATA descriptionBits = 0; if(((UDATA)descriptionPtr) & 1) { descriptionBits = ((UDATA)descriptionPtr) >> 1; } else { diff --git a/runtime/gc_base/ObjectAccessBarrier.hpp b/runtime/gc_base/ObjectAccessBarrier.hpp index bc6a6be491e..96e68d9cb88 100644 --- a/runtime/gc_base/ObjectAccessBarrier.hpp +++ b/runtime/gc_base/ObjectAccessBarrier.hpp @@ -224,6 +224,7 @@ class MM_ObjectAccessBarrier : public MM_BaseVirtual virtual j9objectmonitor_t *getLockwordAddress(J9VMThread *vmThread, J9Object *object); virtual void cloneObject(J9VMThread *vmThread, J9Object *srcObject, J9Object *destObject); virtual void copyObjectFields(J9VMThread *vmThread, J9Class *valueClass, J9Object *srcObject, UDATA srcOffset, J9Object *destObject, UDATA destOffset); + virtual BOOLEAN structuralCompareFlattenedObjects(J9VMThread *vmThread, J9Class *valueClass, j9object_t lhsObject, j9object_t rhsObject, UDATA startOffset); virtual void cloneIndexableObject(J9VMThread *vmThread, J9IndexableObject *srcObject, J9IndexableObject *destObject); virtual J9Object* asConstantPoolObject(J9VMThread *vmThread, J9Object* toConvert, UDATA allocationFlags); virtual void storeObjectToInternalVMSlot(J9VMThread *vmThread, J9Object** destSlot, J9Object *value); diff --git a/runtime/gc_base/accessBarrier.cpp b/runtime/gc_base/accessBarrier.cpp index ff819ae6f9a..dd1e7b31c7f 100644 --- a/runtime/gc_base/accessBarrier.cpp +++ b/runtime/gc_base/accessBarrier.cpp @@ -608,6 +608,16 @@ j9gc_objaccess_cloneObject(J9VMThread *vmThread, J9Object *srcObject, J9Object * return barrier->cloneObject(vmThread, srcObject, destObject); } +/** + * + */ +BOOLEAN +j9gc_objaccess_structuralCompareFlattenedObjects(J9VMThread *vmThread, J9Class *valueClass, j9object_t lhsObject, j9object_t rhsObject, UDATA startOffset) +{ + MM_ObjectAccessBarrier *barrier = MM_GCExtensions::getExtensions(vmThread)->accessBarrier; + return barrier->structuralCompareFlattenedObjects(vmThread, valueClass, lhsObject, rhsObject, startOffset); +} + /** * Called by certain specs to copy objects */ diff --git a/runtime/gc_base/gc_internal.h b/runtime/gc_base/gc_internal.h index a2a83bbbfb6..e308ee92a83 100644 --- a/runtime/gc_base/gc_internal.h +++ b/runtime/gc_base/gc_internal.h @@ -99,6 +99,7 @@ extern J9_CFUNC void j9gc_objaccess_cloneObject(J9VMThread *vmThread, j9object_t extern J9_CFUNC void j9gc_objaccess_copyObjectFields(J9VMThread *vmThread, J9Class *valueClass, J9Object *srcObject, UDATA srcOffset, J9Object *destObject, UDATA destOffset); extern J9_CFUNC void j9gc_objaccess_copyObjectFieldsToFlattenedArrayElement(J9VMThread *vmThread, J9ArrayClass *arrayClazz, j9object_t srcObject, J9IndexableObject *arrayRef, I_32 index); extern J9_CFUNC void j9gc_objaccess_copyObjectFieldsFromFlattenedArrayElement(J9VMThread *vmThread, J9ArrayClass *arrayClazz, j9object_t destObject, J9IndexableObject *arrayRef, I_32 index); +extern J9_CFUNC BOOLEAN j9gc_objaccess_structuralCompareFlattenedObjects(J9VMThread *vmThread, J9Class *valueClass, j9object_t lhsObject, j9object_t rhsObject, UDATA startOffset); extern J9_CFUNC j9object_t j9gc_objaccess_asConstantPoolObject(J9VMThread *vmThread, j9object_t toConvert, UDATA allocationFlags); extern J9_CFUNC jvmtiIterationControl j9mm_iterate_heaps(J9JavaVM *vm, J9PortLibrary *portLibrary, UDATA flags, jvmtiIterationControl(*func)(J9JavaVM *vm, struct J9MM_IterateHeapDescriptor *heapDesc, void *userData), void *userData); extern J9_CFUNC int gcStartupHeapManagement(J9JavaVM * vm); diff --git a/runtime/gc_include/ObjectAccessBarrierAPI.hpp b/runtime/gc_include/ObjectAccessBarrierAPI.hpp index 13dda6499dd..270a9be9187 100644 --- a/runtime/gc_include/ObjectAccessBarrierAPI.hpp +++ b/runtime/gc_include/ObjectAccessBarrierAPI.hpp @@ -392,6 +392,23 @@ class MM_ObjectAccessBarrierAPI vmThread->javaVM->memoryManagerFunctions->j9gc_objaccess_copyObjectFieldsFromFlattenedArrayElement(vmThread, arrayClazz, destObject, arrayRef, (I_32)index); } + VMINLINE BOOLEAN + structuralFlattenedCompareObjects(J9VMThread *vmThread, J9Class *valueClass, j9object_t lhsObject, j9object_t rhsObject, UDATA startOffset) + { +#if defined(J9VM_GC_ALWAYS_CALL_OBJECT_ACCESS_BARRIER) + return vmThread->javaVM->memoryManagerFunctions->j9gc_objaccess_structuralCompareFlattenedObjects(vmThread, valueClass, lhsObject, rhsObject, startOffset); +#else /* defined(J9VM_GC_ALWAYS_CALL_OBJECT_ACCESS_BARRIER) */ + if (j9gc_modron_readbar_none != _readBarrierType) { + return vmThread->javaVM->memoryManagerFunctions->j9gc_objaccess_structuralCompareFlattenedObjects(vmThread, valueClass, lhsObject, rhsObject, startOffset); + } else { + startOffset += valueClass->backfillOffset; + UDATA compareSize = mixedObjectGetDataSize(valueClass) - valueClass->backfillOffset; + + return (0 == memcmp((void*)((UDATA)lhsObject + startOffset), (void*)((UDATA)rhsObject + startOffset), (size_t)compareSize)); + } +#endif /* defined(J9VM_GC_ALWAYS_CALL_OBJECT_ACCESS_BARRIER) */ + } + /** * Copy valueType from sourceObject to destObject * See MM_ObjectAccessBarrier::copyObjectFields for detailed description diff --git a/runtime/oti/j9nonbuilder.h b/runtime/oti/j9nonbuilder.h index f7cfae7c72b..a52f5615a9c 100644 --- a/runtime/oti/j9nonbuilder.h +++ b/runtime/oti/j9nonbuilder.h @@ -4382,6 +4382,7 @@ typedef struct J9MemoryManagerFunctions { void ( *j9gc_objaccess_copyObjectFields)(struct J9VMThread *vmThread, J9Class* valueClass, j9object_t srcObject, UDATA srcOffset, j9object_t destObject, UDATA destOffset) ; void ( *j9gc_objaccess_copyObjectFieldsToFlattenedArrayElement)(struct J9VMThread *vmThread, J9ArrayClass *arrayClazz, j9object_t srcObject, J9IndexableObject *arrayRef, I_32 index) ; void ( *j9gc_objaccess_copyObjectFieldsFromFlattenedArrayElement)(struct J9VMThread *vmThread, J9ArrayClass *arrayClazz, j9object_t destObject, J9IndexableObject *arrayRef, I_32 index) ; + BOOLEAN ( *j9gc_objaccess_structuralCompareFlattenedObjects)(struct J9VMThread *vmThread, J9Class *valueClass, j9object_t lhsObject, j9object_t rhsObject, UDATA startOffset) ; void ( *j9gc_objaccess_cloneIndexableObject)(struct J9VMThread *vmThread, J9IndexableObject *srcObject, J9IndexableObject *destObject) ; j9object_t ( *j9gc_objaccess_asConstantPoolObject)(struct J9VMThread *vmThread, j9object_t toConvert, UDATA allocationFlags) ; #if defined(J9VM_GC_REALTIME) diff --git a/runtime/vm/BytecodeInterpreter.hpp b/runtime/vm/BytecodeInterpreter.hpp index 85bb43e4b42..134707eee05 100644 --- a/runtime/vm/BytecodeInterpreter.hpp +++ b/runtime/vm/BytecodeInterpreter.hpp @@ -5821,7 +5821,7 @@ done:; } else { j9object_t value = NULL; #if defined(J9VM_OPT_VALHALLA_VALUE_TYPES) - J9ArrayClass *arrayrefClass = J9OBJECT_CLAZZ(_currentThread, arrayref); + J9Class *arrayrefClass = J9OBJECT_CLAZZ(_currentThread, arrayref); if (J9_IS_J9CLASS_FLATTENED(arrayrefClass)) { j9object_t newObjectRef = _objectAllocate.inlineAllocateObject(_currentThread, ((J9ArrayClass*)arrayrefClass)->leafComponentType, false, false); @@ -5840,7 +5840,7 @@ done:; arrayrefClass = VM_VMHelpers::currentClass(arrayrefClass); } - _objectAccessBarrier.copyObjectFieldsFromFlattenedArrayElement(_currentThread, arrayrefClass, newObjectRef, (J9IndexableObject *) arrayref, index); + _objectAccessBarrier.copyObjectFieldsFromFlattenedArrayElement(_currentThread, (J9ArrayClass *) arrayrefClass, newObjectRef, (J9IndexableObject *) arrayref, index); value = newObjectRef; } else #endif /* if defined(J9VM_OPT_VALHALLA_VALUE_TYPES) */ @@ -5879,9 +5879,9 @@ done:; rc = THROW_ARRAY_STORE; } else { #if defined(J9VM_OPT_VALHALLA_VALUE_TYPES) - J9ArrayClass *arrayrefClass = J9OBJECT_CLAZZ(_currentThread, arrayref); + J9Class *arrayrefClass = J9OBJECT_CLAZZ(_currentThread, arrayref); if (J9_IS_J9CLASS_FLATTENED(arrayrefClass)) { - _objectAccessBarrier.copyObjectFieldsToFlattenedArrayElement(_currentThread, arrayrefClass, value, (J9IndexableObject *) arrayref, index); + _objectAccessBarrier.copyObjectFieldsToFlattenedArrayElement(_currentThread, (J9ArrayClass *) arrayrefClass, value, (J9IndexableObject *) arrayref, index); } else #endif /* if defined(J9VM_OPT_VALHALLA_VALUE_TYPES) */ {