Path: blob/master/runtime/gc_include/ObjectAllocationAPI.hpp
5986 views
/*******************************************************************************1* Copyright (c) 1991, 2021 IBM Corp. and others2*3* This program and the accompanying materials are made available under4* the terms of the Eclipse Public License 2.0 which accompanies this5* distribution and is available at https://www.eclipse.org/legal/epl-2.0/6* or the Apache License, Version 2.0 which accompanies this distribution and7* is available at https://www.apache.org/licenses/LICENSE-2.0.8*9* This Source Code may also be made available under the following10* Secondary Licenses when the conditions for such availability set11* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU12* General Public License, version 2 with the GNU Classpath13* Exception [1] and GNU General Public License, version 2 with the14* OpenJDK Assembly Exception [2].15*16* [1] https://www.gnu.org/software/classpath/license.html17* [2] http://openjdk.java.net/legal/assembly-exception.html18*19* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception20*******************************************************************************/2122#if !defined(OBJECTALLOCATIONAPI_HPP_)23#define OBJECTALLOCATIONAPI_HPP_2425#include "j9cfg.h"2627#if defined(OMR_OVERRIDE_COMPRESS_OBJECT_REFERENCES)28#if OMR_OVERRIDE_COMPRESS_OBJECT_REFERENCES29#define MM_ObjectAllocationAPI MM_ObjectAllocationAPICompressed30#else /* OMR_OVERRIDE_COMPRESS_OBJECT_REFERENCES */31#define MM_ObjectAllocationAPI MM_ObjectAllocationAPIFull32#endif /* OMR_OVERRIDE_COMPRESS_OBJECT_REFERENCES */33#endif /* OMR_OVERRIDE_COMPRESS_OBJECT_REFERENCES */3435#include "j9.h"36#include "j9consts.h"37#include "j9generated.h"38#include "j9protos.h"39#include "omrgcconsts.h"4041#include "AtomicSupport.hpp"42#include "ObjectMonitor.hpp"4344class MM_ObjectAllocationAPI45{46/*47* Data members48*/49private:50const uintptr_t _gcAllocationType;51#if defined(J9VM_GC_BATCH_CLEAR_TLH)52const uintptr_t _initializeSlotsOnTLHAllocate;53#endif /* J9VM_GC_BATCH_CLEAR_TLH */54const uintptr_t _objectAlignmentInBytes;5556#if defined (J9VM_GC_SEGREGATED_HEAP)57const J9VMGCSizeClasses *_sizeClasses;58#endif /* J9VM_GC_SEGREGATED_HEAP */5960VMINLINE void61initializeIndexableSlots(bool initializeSlots, uintptr_t dataSize, void *dataAddr)62{63if (initializeSlots) {64memset(dataAddr, 0, dataSize);65}66}6768VMINLINE void69initializeContiguousIndexableObject(J9VMThread *currentThread, bool initializeSlots, J9Class *arrayClass, uint32_t size, uintptr_t dataSize, j9object_t *objectHeader)70{71bool isCompressedReferences = J9VMTHREAD_COMPRESS_OBJECT_REFERENCES(currentThread);7273if (isCompressedReferences) {74uintptr_t headerSize = sizeof(J9IndexableObjectContiguousCompressed);75J9IndexableObjectContiguousCompressed *header = (J9IndexableObjectContiguousCompressed*)*objectHeader;76header->clazz = (uint32_t)(uintptr_t)arrayClass;77header->size = size;78void *dataAddr = (void *)((uintptr_t)header + headerSize);79#if defined(J9VM_ENV_DATA64)80header->dataAddr = dataAddr;81#endif /* J9VM_ENV_DATA64 */82initializeIndexableSlots(initializeSlots, dataSize, dataAddr);83} else {84uintptr_t headerSize = sizeof(J9IndexableObjectContiguousFull);85J9IndexableObjectContiguousFull *header = (J9IndexableObjectContiguousFull*)*objectHeader;86header->clazz = (uintptr_t)arrayClass;87header->size = size;88void *dataAddr = (void *)((uintptr_t)header + headerSize);89#if defined(J9VM_ENV_DATA64)90header->dataAddr = dataAddr;91#endif /* J9VM_ENV_DATA64 */92initializeIndexableSlots(initializeSlots, dataSize, dataAddr);93}94}9596VMINLINE void97initializeDiscontiguousIndexableObject(J9VMThread *currentThread, J9Class *arrayClass, j9object_t *objectHeader)98{99bool isCompressedReferences = J9VMTHREAD_COMPRESS_OBJECT_REFERENCES(currentThread);100101if (isCompressedReferences) {102J9IndexableObjectDiscontiguousCompressed *header = (J9IndexableObjectDiscontiguousCompressed*)*objectHeader;103header->clazz = (uint32_t)(uintptr_t)arrayClass;104header->mustBeZero = 0;105header->size = 0;106#if defined(J9VM_ENV_DATA64)107uintptr_t headerSize = sizeof(J9IndexableObjectDiscontiguousCompressed);108header->dataAddr = (void *)((uintptr_t)header + headerSize);109#endif /* J9VM_ENV_DATA64 */110} else {111J9IndexableObjectDiscontiguousFull *header = (J9IndexableObjectDiscontiguousFull*)*objectHeader;112header->clazz = (uintptr_t)arrayClass;113header->mustBeZero = 0;114header->size = 0;115#if defined(J9VM_ENV_DATA64)116uintptr_t headerSize = sizeof(J9IndexableObjectDiscontiguousFull);117header->dataAddr = (void *)((uintptr_t)header + headerSize);118#endif /* J9VM_ENV_DATA64 */119}120}121122protected:123public:124125/*126* Function members127*/128private:129130VMINLINE j9object_t131inlineAllocateIndexableObjectImpl(J9VMThread *currentThread, J9Class *arrayClass, uint32_t size, uintptr_t dataSize, bool validSize, bool initializeSlots = true, bool memoryBarrier = true)132{133j9object_t instance = NULL;134135#if defined(J9VM_GC_THREAD_LOCAL_HEAP) || defined(J9VM_GC_SEGREGATED_HEAP)136if (0 != size) {137/* Contiguous Array */138139#if !defined(J9VM_ENV_DATA64)140if (validSize)141#endif /* J9VM_ENV_DATA64 */142{143/* Calculate the size of the object */144uintptr_t const headerSize = J9VMTHREAD_CONTIGUOUS_HEADER_SIZE(currentThread);145uintptr_t const dataSize = ((uintptr_t)size) * J9ARRAYCLASS_GET_STRIDE(arrayClass);146uintptr_t allocateSize = ROUND_UP_TO_POWEROF2(dataSize + headerSize, _objectAlignmentInBytes);147#if defined(J9VM_ENV_DATA64)148if (allocateSize < J9_GC_MINIMUM_INDEXABLE_OBJECT_SIZE) {149allocateSize = J9_GC_MINIMUM_INDEXABLE_OBJECT_SIZE;150}151#else /* !J9VM_ENV_DATA64 */152if (allocateSize < J9_GC_MINIMUM_OBJECT_SIZE) {153allocateSize = J9_GC_MINIMUM_OBJECT_SIZE;154}155#endif /* J9VM_ENV_DATA64 */156/* Allocate the memory */157j9object_t objectHeader = NULL;158159switch(_gcAllocationType) {160161#if defined(J9VM_GC_THREAD_LOCAL_HEAP)162case OMR_GC_ALLOCATION_TYPE_TLH:163if (allocateSize <= ((uintptr_t) currentThread->heapTop - (uintptr_t) currentThread->heapAlloc)) {164uint8_t *heapAlloc = currentThread->heapAlloc;165uint8_t *afterAlloc = heapAlloc + allocateSize;166objectHeader = (j9object_t)heapAlloc;167currentThread->heapAlloc = afterAlloc;168#if defined(J9VM_GC_TLH_PREFETCH_FTA)169currentThread->tlhPrefetchFTA -= allocateSize;170#endif /* J9VM_GC_TLH_PREFETCH_FTA */171#if defined(J9VM_GC_BATCH_CLEAR_TLH)172/* Do not zero the TLH if it is already zero's */173initializeSlots = initializeSlots && _initializeSlotsOnTLHAllocate;174#endif /* J9VM_GC_BATCH_CLEAR_TLH */175} else {176return NULL;177}178break;179#endif /* J9VM_GC_THREAD_LOCAL_HEAP */180181#if defined(J9VM_GC_SEGREGATED_HEAP)182183case OMR_GC_ALLOCATION_TYPE_SEGREGATED:184/* Metronome requires that slots are always initialized */185186/* ensure the allocation will fit in a small size */187if (allocateSize <= J9VMGC_SIZECLASSES_MAX_SMALL_SIZE_BYTES) {188189/* fetch the size class based on the allocation size */190uintptr_t slotsRequested = allocateSize / sizeof(uintptr_t);191uintptr_t sizeClassIndex = _sizeClasses->sizeClassIndex[slotsRequested];192193/* Ensure the cache for the current size class is not empty. */194J9VMGCSegregatedAllocationCacheEntry *cacheEntry =195(J9VMGCSegregatedAllocationCacheEntry *)((uintptr_t)currentThread + J9_VMTHREAD_SEGREGATED_ALLOCATION_CACHE_OFFSET196+ (sizeClassIndex * sizeof(J9VMGCSegregatedAllocationCacheEntry)));197uintptr_t cellSize = _sizeClasses->smallCellSizes[sizeClassIndex];198199if (cellSize <= ((uintptr_t) cacheEntry->top - (uintptr_t) cacheEntry->current)) {200objectHeader = (j9object_t)cacheEntry->current;201cacheEntry->current = (uintptr_t *) ((uintptr_t) cacheEntry->current + cellSize);202/* The metronome pre write barrier might scan this object - always zero it */203initializeSlots = true;204} else {205return NULL;206}207} else {208return NULL;209}210break;211#endif /* J9VM_GC_SEGREGATED_HEAP */212213default:214/* Inline allocation not supported */215return NULL;216}217218/* Initialize the object */219initializeContiguousIndexableObject(currentThread, initializeSlots, arrayClass, size, dataSize, &objectHeader);220221if (memoryBarrier) {222VM_AtomicSupport::writeBarrier();223}224instance = objectHeader;225}226} else {227#if defined(J9VM_ENV_DATA64)228/* Calculate size of indexable object */229uintptr_t const headerSize = J9VMTHREAD_DISCONTIGUOUS_HEADER_SIZE(currentThread);230uintptr_t allocateSize = ROUND_UP_TO_POWEROF2(headerSize, _objectAlignmentInBytes);231/* Discontiguous header size is always equal or greater than J9_GC_MINIMUM_INDEXABLE_OBJECT_SIZE; therefore,232* there's no need to check if allocateSize is less than J9_GC_MINIMUM_INDEXABLE_OBJECT_SIZE233*/234#else235/* Zero-length array is discontiguous - assume minimum object size */236uintptr_t allocateSize = J9_GC_MINIMUM_OBJECT_SIZE;237#endif /* J9VM_ENV_DATA64 */238239/* Allocate the memory */240j9object_t objectHeader = NULL;241switch(_gcAllocationType) {242243#if defined(J9VM_GC_THREAD_LOCAL_HEAP)244case OMR_GC_ALLOCATION_TYPE_TLH:245246if (allocateSize <= ((uintptr_t) currentThread->heapTop - (uintptr_t) currentThread->heapAlloc)) {247uint8_t *heapAlloc = currentThread->heapAlloc;248uint8_t *afterAlloc = heapAlloc + allocateSize;249objectHeader = (j9object_t) heapAlloc;250currentThread->heapAlloc = afterAlloc;251#if defined(J9VM_GC_TLH_PREFETCH_FTA)252currentThread->tlhPrefetchFTA -= allocateSize;253#endif /* J9VM_GC_TLH_PREFETCH_FTA */254} else {255return NULL;256}257break;258#endif /* J9VM_GC_THREAD_LOCAL_HEAP */259260#if defined(J9VM_GC_SEGREGATED_HEAP)261case OMR_GC_ALLOCATION_TYPE_SEGREGATED:262/* ensure the allocation will fit in a small size */263if (allocateSize <= J9VMGC_SIZECLASSES_MAX_SMALL_SIZE_BYTES) {264265/* fetch the size class based on the allocation size */266uintptr_t slotsRequested = allocateSize / sizeof(uintptr_t);267uintptr_t sizeClassIndex = _sizeClasses->sizeClassIndex[slotsRequested];268269/* Ensure the cache for the current size class is not empty. */270J9VMGCSegregatedAllocationCacheEntry *cacheEntry =271(J9VMGCSegregatedAllocationCacheEntry *)((uintptr_t)currentThread + J9_VMTHREAD_SEGREGATED_ALLOCATION_CACHE_OFFSET272+ (sizeClassIndex * sizeof(J9VMGCSegregatedAllocationCacheEntry)));273uintptr_t cellSize = _sizeClasses->smallCellSizes[sizeClassIndex];274275if (cellSize <= ((uintptr_t) cacheEntry->top - (uintptr_t) cacheEntry->current)) {276objectHeader = (j9object_t) cacheEntry->current;277cacheEntry->current = (uintptr_t *) ((uintptr_t) cacheEntry->current + cellSize);278} else {279return NULL;280}281} else {282return NULL;283}284break;285#endif /* J9VM_GC_SEGREGATED_HEAP */286287default:288return NULL;289break;290}291292/* Initialize the object */293initializeDiscontiguousIndexableObject(currentThread, arrayClass, &objectHeader);294295if (memoryBarrier) {296VM_AtomicSupport::writeBarrier();297}298instance = objectHeader;299300#endif /* defined(J9VM_GC_THREAD_LOCAL_HEAP) || defined(J9VM_GC_SEGREGATED_HEAP) */301302}303304return instance;305}306307protected:308public:309310/**311* Create an instance.312*/313MM_ObjectAllocationAPI(J9VMThread *currentThread)314: _gcAllocationType(currentThread->javaVM->gcAllocationType)315#if defined(J9VM_GC_BATCH_CLEAR_TLH)316, _initializeSlotsOnTLHAllocate(currentThread->javaVM->initializeSlotsOnTLHAllocate)317#endif /* J9VM_GC_BATCH_CLEAR_TLH */318, _objectAlignmentInBytes(currentThread->omrVMThread->_vm->_objectAlignmentInBytes)319#if defined (J9VM_GC_SEGREGATED_HEAP)320, _sizeClasses(currentThread->javaVM->realtimeSizeClasses)321#endif /* J9VM_GC_SEGREGATED_HEAP */322{}323324VMINLINE j9object_t325inlineAllocateObject(J9VMThread *currentThread, J9Class *clazz, bool initializeSlots = true, bool memoryBarrier = true)326{327j9object_t instance = NULL;328#if defined(J9VM_GC_THREAD_LOCAL_HEAP) || defined(J9VM_GC_SEGREGATED_HEAP)329/* Calculate the size of the object */330uintptr_t const headerSize = J9VMTHREAD_OBJECT_HEADER_SIZE(currentThread);331uintptr_t dataSize = clazz->totalInstanceSize;332uintptr_t allocateSize = ROUND_UP_TO_POWEROF2(dataSize + headerSize, _objectAlignmentInBytes);333if (allocateSize < J9_GC_MINIMUM_OBJECT_SIZE) {334allocateSize = J9_GC_MINIMUM_OBJECT_SIZE;335}336337/* Allocate the object */338switch(_gcAllocationType) {339#if defined(J9VM_GC_THREAD_LOCAL_HEAP)340case OMR_GC_ALLOCATION_TYPE_TLH:341if (allocateSize <= ((uintptr_t) currentThread->heapTop - (uintptr_t) currentThread->heapAlloc)) {342uint8_t *heapAlloc = currentThread->heapAlloc;343uint8_t *afterAlloc = heapAlloc + allocateSize;344currentThread->heapAlloc = afterAlloc;345#if defined(J9VM_GC_TLH_PREFETCH_FTA)346currentThread->tlhPrefetchFTA -= allocateSize;347#endif /* J9VM_GC_TLH_PREFETCH_FTA */348instance = (j9object_t) heapAlloc;349#if defined(J9VM_GC_BATCH_CLEAR_TLH)350/* Do not zero the TLH if it is already zero'd */351initializeSlots = initializeSlots && _initializeSlotsOnTLHAllocate;352#endif /* J9VM_GC_BATCH_CLEAR_TLH */353} else {354return NULL;355}356break;357#endif /* J9VM_GC_THREAD_LOCAL_HEAP */358359#if defined(J9VM_GC_SEGREGATED_HEAP)360case OMR_GC_ALLOCATION_TYPE_SEGREGATED:361/* ensure the allocation will fit in a small size */362if (allocateSize <= J9VMGC_SIZECLASSES_MAX_SMALL_SIZE_BYTES) {363364/* fetch the size class based on the allocation size */365uintptr_t slotsRequested = allocateSize / sizeof(uintptr_t);366uintptr_t sizeClassIndex = _sizeClasses->sizeClassIndex[slotsRequested];367368/* Ensure the cache for the current size class is not empty. */369J9VMGCSegregatedAllocationCacheEntry *cacheEntry =370(J9VMGCSegregatedAllocationCacheEntry *)((uintptr_t)currentThread + J9_VMTHREAD_SEGREGATED_ALLOCATION_CACHE_OFFSET371+ (sizeClassIndex * sizeof(J9VMGCSegregatedAllocationCacheEntry)));372uintptr_t cellSize = _sizeClasses->smallCellSizes[sizeClassIndex];373374if (cellSize <= ((uintptr_t) cacheEntry->top - (uintptr_t) cacheEntry->current)) {375instance = (j9object_t) cacheEntry->current;376cacheEntry->current = (uintptr_t *) ((uintptr_t) cacheEntry->current + cellSize);377/* The metronome pre write barrier might scan this object - always zero it */378initializeSlots = true;379} else {380return NULL;381}382} else {383return NULL;384}385break;386#endif /* J9VM_GC_SEGREGATED_HEAP */387388default:389return NULL;390}391392/* Initialize the object */393if (J9VMTHREAD_COMPRESS_OBJECT_REFERENCES(currentThread)) {394J9ObjectCompressed *objectHeader = (J9ObjectCompressed*) instance;395if (J9CLASS_IS_ENSUREHASHED(clazz)) {396objectHeader->clazz = (uint32_t)(uintptr_t)clazz | (uint32_t)OBJECT_HEADER_HAS_BEEN_HASHED_IN_CLASS;397} else {398objectHeader->clazz = (uint32_t)(uintptr_t)clazz;399}400if (initializeSlots) {401memset(objectHeader + 1, 0, dataSize);402}403} else {404J9ObjectFull *objectHeader = (J9ObjectFull*) instance;405if (J9CLASS_IS_ENSUREHASHED(clazz)) {406objectHeader->clazz = (uintptr_t)clazz | (uintptr_t)OBJECT_HEADER_HAS_BEEN_HASHED_IN_CLASS;407} else {408objectHeader->clazz = (uintptr_t)clazz;409}410if (initializeSlots) {411memset(objectHeader + 1, 0, dataSize);412}413}414415if (initializeSlots) {416if (LN_HAS_LOCKWORD(currentThread, instance)) {417j9objectmonitor_t initialLockword = VM_ObjectMonitor::getInitialLockword(currentThread->javaVM, clazz);418if (0 != initialLockword) {419j9objectmonitor_t *lockEA = J9OBJECT_MONITOR_EA(currentThread, instance);420J9_STORE_LOCKWORD(currentThread, lockEA, initialLockword);421}422}423}424425if (memoryBarrier) {426VM_AtomicSupport::writeBarrier();427}428#endif /* J9VM_GC_THREAD_LOCAL_HEAP || J9VM_GC_SEGREGATED_HEAP */429return instance;430}431432VMINLINE j9object_t433inlineAllocateIndexableValueTypeObject(J9VMThread *currentThread, J9Class *arrayClass, uint32_t size, bool initializeSlots = true, bool memoryBarrier = true, bool sizeCheck = true)434{435uintptr_t dataSize = ((uintptr_t)size) * J9ARRAYCLASS_GET_STRIDE(arrayClass);436bool validSize = true;437#if !defined(J9VM_ENV_DATA64)438validSize = !sizeCheck || (size < ((uint32_t)J9_MAXIMUM_INDEXABLE_DATA_SIZE / J9ARRAYCLASS_GET_STRIDE(arrayClass)));439#endif /* J9VM_ENV_DATA64 */440return inlineAllocateIndexableObjectImpl(currentThread, arrayClass, size, dataSize, validSize, initializeSlots, memoryBarrier);441}442443VMINLINE j9object_t444inlineAllocateIndexableObject(J9VMThread *currentThread, J9Class *arrayClass, uint32_t size, bool initializeSlots = true, bool memoryBarrier = true, bool sizeCheck = true)445{446uintptr_t scale = ((J9ROMArrayClass*)(arrayClass->romClass))->arrayShape;447uintptr_t dataSize = ((uintptr_t)size) << scale;448bool validSize = true;449#if !defined(J9VM_ENV_DATA64)450validSize = !sizeCheck || (size < ((uint32_t)J9_MAXIMUM_INDEXABLE_DATA_SIZE >> scale));451#endif /* J9VM_ENV_DATA64 */452return inlineAllocateIndexableObjectImpl(currentThread, arrayClass, size, dataSize, validSize, initializeSlots, memoryBarrier);453}454455};456457#endif /* OBJECTALLOCATIONAPI_HPP_ */458459460