From f995f59016239e880bc6e90e8a1ddeabfef935b4 Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Mon, 20 Oct 2025 10:08:38 +0200 Subject: [PATCH 1/7] Add RhpNewFast allocators --- src/coreclr/runtime/portable/AllocFast.cpp | 96 ++++++++++++++++++++-- 1 file changed, 90 insertions(+), 6 deletions(-) diff --git a/src/coreclr/runtime/portable/AllocFast.cpp b/src/coreclr/runtime/portable/AllocFast.cpp index d9c27f9248dd53..11be318515d626 100644 --- a/src/coreclr/runtime/portable/AllocFast.cpp +++ b/src/coreclr/runtime/portable/AllocFast.cpp @@ -146,20 +146,104 @@ EXTERN_C FCDECL2(Object*, RhpNewPtrArrayFast, MethodTable* pMT, INT_PTR size) EXTERN_C FCDECL1(Object*, RhpNewFast, MethodTable* pMT) { - PORTABILITY_ASSERT("RhpNewFast is not yet implemented"); - return nullptr; + FCALL_CONTRACT; + _ASSERTE(pMT != NULL); + + Thread* thread = GetThread(); + ee_alloc_context* cxt = thread->GetEEAllocContext(); + + size_t sizeInBytes = (size_t)pMT->GetBaseSize(); + sizeInBytes = ALIGN_UP(sizeInBytes, sizeof(void*)); + + uint8_t* alloc_ptr = cxt->getAllocPtr(); + _ASSERTE(alloc_ptr <= cxt->getAllocLimit()); + if ((size_t)(cxt->getAllocLimit() - alloc_ptr) >= sizeInBytes) + { + cxt->setAllocPtr(alloc_ptr + sizeInBytes); + PtrArray* pObject = (PtrArray *)alloc_ptr; + pObject->SetMethodTable(pMT); + return pObject; + } + + return AllocateObject(pMT, 0, 0); } EXTERN_C FCDECL1(Object*, RhpNewFastAlign8, MethodTable* pMT) { - PORTABILITY_ASSERT("RhpNewFastAlign8 is not yet implemented"); - return nullptr; + FCALL_CONTRACT; + _ASSERTE(pMT != NULL); + + Thread* thread = GetThread(); + ee_alloc_context* cxt = thread->GetEEAllocContext(); + + size_t sizeInBytes = (size_t)pMT->GetBaseSize(); + sizeInBytes = ALIGN_UP(sizeInBytes, sizeof(void*)); + + uint8_t* alloc_ptr = cxt->getAllocPtr(); + bool requiresAlignObject = !IS_ALIGNED(alloc_ptr, sizeof(int64_t)); + size_t paddedSize = sizeInBytes; + if (requiresAlignObject) + { + // We are assuming that allocation of minimal object flips the alignment + paddedSize += MIN_OBJECT_SIZE; + } + + _ASSERTE(alloc_ptr <= cxt->getAllocLimit()); + if ((size_t)(cxt->getAllocLimit() - alloc_ptr) >= sizeInBytes) + { + cxt->setAllocPtr(alloc_ptr + paddedSize); + if (requiresAlignObject) + { + Object* dummy = (Object*)alloc_ptr; + dummy->SetMethodTable(g_pFreeObjectMethodTable); + alloc_ptr += MIN_OBJECT_SIZE; + } + PtrArray* pObject = (PtrArray *)alloc_ptr; + pObject->SetMethodTable(pMT); + return pObject; + } + + return AllocateObject(pMT, GC_ALLOC_ALIGN8, 0); } EXTERN_C FCDECL1(Object*, RhpNewFastMisalign, MethodTable* pMT) { - PORTABILITY_ASSERT("RhpNewFastMisalign is not yet implemented"); - return nullptr; + FCALL_CONTRACT; + _ASSERTE(pMT != NULL); + + Thread* thread = GetThread(); + ee_alloc_context* cxt = thread->GetEEAllocContext(); + + size_t sizeInBytes = (size_t)pMT->GetBaseSize(); + sizeInBytes = ALIGN_UP(sizeInBytes, sizeof(void*)); + + uint8_t* alloc_ptr = cxt->getAllocPtr(); + bool requiresAlignObject = IS_ALIGNED(alloc_ptr, sizeof(int64_t)); + size_t paddedSize = sizeInBytes; + if (requiresAlignObject) + { + // We are assuming that allocation of minimal object flips the alignment + paddedSize += MIN_OBJECT_SIZE; + } else { + _ASSERTE((((uint32_t)alloc_ptr) & (sizeof(int64_t) - 1)) == sizeof(int32_t)); + } + + _ASSERTE(alloc_ptr <= cxt->getAllocLimit()); + if ((size_t)(cxt->getAllocLimit() - alloc_ptr) >= sizeInBytes) + { + cxt->setAllocPtr(alloc_ptr + paddedSize); + if (requiresAlignObject) + { + Object* dummy = (Object*)alloc_ptr; + dummy->SetMethodTable(g_pFreeObjectMethodTable); + alloc_ptr += MIN_OBJECT_SIZE; + } + PtrArray* pObject = (PtrArray *)alloc_ptr; + pObject->SetMethodTable(pMT); + return pObject; + } + + return AllocateObject(pMT, GC_ALLOC_ALIGN8 | GC_ALLOC_ALIGN8_BIAS, 0); } #define MAX_STRING_LENGTH 0x3FFFFFDF From e93072c5a626c698b657d5965f9dc19c4327a508 Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Mon, 20 Oct 2025 14:31:02 +0200 Subject: [PATCH 2/7] Feedback --- src/coreclr/runtime/portable/AllocFast.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/coreclr/runtime/portable/AllocFast.cpp b/src/coreclr/runtime/portable/AllocFast.cpp index 11be318515d626..29eb6a9dae5b68 100644 --- a/src/coreclr/runtime/portable/AllocFast.cpp +++ b/src/coreclr/runtime/portable/AllocFast.cpp @@ -189,7 +189,7 @@ EXTERN_C FCDECL1(Object*, RhpNewFastAlign8, MethodTable* pMT) } _ASSERTE(alloc_ptr <= cxt->getAllocLimit()); - if ((size_t)(cxt->getAllocLimit() - alloc_ptr) >= sizeInBytes) + if ((size_t)(cxt->getAllocLimit() - alloc_ptr) >= paddedSize) { cxt->setAllocPtr(alloc_ptr + paddedSize); if (requiresAlignObject) @@ -224,12 +224,14 @@ EXTERN_C FCDECL1(Object*, RhpNewFastMisalign, MethodTable* pMT) { // We are assuming that allocation of minimal object flips the alignment paddedSize += MIN_OBJECT_SIZE; - } else { + } + else + { _ASSERTE((((uint32_t)alloc_ptr) & (sizeof(int64_t) - 1)) == sizeof(int32_t)); } _ASSERTE(alloc_ptr <= cxt->getAllocLimit()); - if ((size_t)(cxt->getAllocLimit() - alloc_ptr) >= sizeInBytes) + if ((size_t)(cxt->getAllocLimit() - alloc_ptr) >= paddedSize) { cxt->setAllocPtr(alloc_ptr + paddedSize); if (requiresAlignObject) From 88d05b41927aa683cd7003bb4c02a6823e5755ec Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Tue, 21 Oct 2025 20:29:46 +0200 Subject: [PATCH 3/7] Feedback Co-authored-by: Jan Kotas Co-authored-by: Aaron R Robinson --- src/coreclr/runtime/portable/AllocFast.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/coreclr/runtime/portable/AllocFast.cpp b/src/coreclr/runtime/portable/AllocFast.cpp index 29eb6a9dae5b68..080666bcaeb8b2 100644 --- a/src/coreclr/runtime/portable/AllocFast.cpp +++ b/src/coreclr/runtime/portable/AllocFast.cpp @@ -153,14 +153,13 @@ EXTERN_C FCDECL1(Object*, RhpNewFast, MethodTable* pMT) ee_alloc_context* cxt = thread->GetEEAllocContext(); size_t sizeInBytes = (size_t)pMT->GetBaseSize(); - sizeInBytes = ALIGN_UP(sizeInBytes, sizeof(void*)); uint8_t* alloc_ptr = cxt->getAllocPtr(); _ASSERTE(alloc_ptr <= cxt->getAllocLimit()); if ((size_t)(cxt->getAllocLimit() - alloc_ptr) >= sizeInBytes) { cxt->setAllocPtr(alloc_ptr + sizeInBytes); - PtrArray* pObject = (PtrArray *)alloc_ptr; + PtrArray* pObject = (PtrArray*)alloc_ptr; pObject->SetMethodTable(pMT); return pObject; } @@ -177,7 +176,6 @@ EXTERN_C FCDECL1(Object*, RhpNewFastAlign8, MethodTable* pMT) ee_alloc_context* cxt = thread->GetEEAllocContext(); size_t sizeInBytes = (size_t)pMT->GetBaseSize(); - sizeInBytes = ALIGN_UP(sizeInBytes, sizeof(void*)); uint8_t* alloc_ptr = cxt->getAllocPtr(); bool requiresAlignObject = !IS_ALIGNED(alloc_ptr, sizeof(int64_t)); @@ -198,7 +196,7 @@ EXTERN_C FCDECL1(Object*, RhpNewFastAlign8, MethodTable* pMT) dummy->SetMethodTable(g_pFreeObjectMethodTable); alloc_ptr += MIN_OBJECT_SIZE; } - PtrArray* pObject = (PtrArray *)alloc_ptr; + PtrArray* pObject = (PtrArray*)alloc_ptr; pObject->SetMethodTable(pMT); return pObject; } @@ -215,7 +213,6 @@ EXTERN_C FCDECL1(Object*, RhpNewFastMisalign, MethodTable* pMT) ee_alloc_context* cxt = thread->GetEEAllocContext(); size_t sizeInBytes = (size_t)pMT->GetBaseSize(); - sizeInBytes = ALIGN_UP(sizeInBytes, sizeof(void*)); uint8_t* alloc_ptr = cxt->getAllocPtr(); bool requiresAlignObject = IS_ALIGNED(alloc_ptr, sizeof(int64_t)); @@ -240,7 +237,7 @@ EXTERN_C FCDECL1(Object*, RhpNewFastMisalign, MethodTable* pMT) dummy->SetMethodTable(g_pFreeObjectMethodTable); alloc_ptr += MIN_OBJECT_SIZE; } - PtrArray* pObject = (PtrArray *)alloc_ptr; + PtrArray* pObject = (PtrArray*)alloc_ptr; pObject->SetMethodTable(pMT); return pObject; } From 40d5a48c03b1d15aabcaed2d81fe4b71571da66c Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Tue, 21 Oct 2025 21:57:25 +0200 Subject: [PATCH 4/7] Feedback --- src/coreclr/runtime/portable/AllocFast.cpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/coreclr/runtime/portable/AllocFast.cpp b/src/coreclr/runtime/portable/AllocFast.cpp index 080666bcaeb8b2..4d8397dd95d6cc 100644 --- a/src/coreclr/runtime/portable/AllocFast.cpp +++ b/src/coreclr/runtime/portable/AllocFast.cpp @@ -76,19 +76,20 @@ static Object* NewArrayFastAlign8Core(MethodTable* pMT, INT_PTR size) sizeInBytes = ALIGN_UP(sizeInBytes, sizeof(void*)); uint8_t* alloc_ptr = cxt->getAllocPtr(); - bool requiresAlignObject = !IS_ALIGNED(alloc_ptr, sizeof(int64_t)); + bool requiresPadding = !IS_ALIGNED(alloc_ptr, sizeof(int64_t)); size_t paddedSize = sizeInBytes; - if (requiresAlignObject) + if (requiresPadding) { // We are assuming that allocation of minimal object flips the alignment paddedSize += MIN_OBJECT_SIZE; + _ASSERTE(IS_ALIGNED(alloc_ptr + MIN_OBJECT_SIZE, sizeof(int64_t))); } _ASSERTE(alloc_ptr <= cxt->getAllocLimit()); if ((size_t)(cxt->getAllocLimit() - alloc_ptr) >= paddedSize) { cxt->setAllocPtr(alloc_ptr + paddedSize); - if (requiresAlignObject) + if (requiresPadding) { Object* dummy = (Object*)alloc_ptr; dummy->SetMethodTable(g_pFreeObjectMethodTable); @@ -178,19 +179,20 @@ EXTERN_C FCDECL1(Object*, RhpNewFastAlign8, MethodTable* pMT) size_t sizeInBytes = (size_t)pMT->GetBaseSize(); uint8_t* alloc_ptr = cxt->getAllocPtr(); - bool requiresAlignObject = !IS_ALIGNED(alloc_ptr, sizeof(int64_t)); + bool requiresPadding = !IS_ALIGNED(alloc_ptr, sizeof(int64_t)); size_t paddedSize = sizeInBytes; - if (requiresAlignObject) + if (requiresPadding) { // We are assuming that allocation of minimal object flips the alignment paddedSize += MIN_OBJECT_SIZE; + _ASSERTE(IS_ALIGNED(alloc_ptr + MIN_OBJECT_SIZE, sizeof(int64_t))); } _ASSERTE(alloc_ptr <= cxt->getAllocLimit()); if ((size_t)(cxt->getAllocLimit() - alloc_ptr) >= paddedSize) { cxt->setAllocPtr(alloc_ptr + paddedSize); - if (requiresAlignObject) + if (requiresPadding) { Object* dummy = (Object*)alloc_ptr; dummy->SetMethodTable(g_pFreeObjectMethodTable); @@ -215,12 +217,13 @@ EXTERN_C FCDECL1(Object*, RhpNewFastMisalign, MethodTable* pMT) size_t sizeInBytes = (size_t)pMT->GetBaseSize(); uint8_t* alloc_ptr = cxt->getAllocPtr(); - bool requiresAlignObject = IS_ALIGNED(alloc_ptr, sizeof(int64_t)); + bool requiresPadding = IS_ALIGNED(alloc_ptr, sizeof(int64_t)); size_t paddedSize = sizeInBytes; - if (requiresAlignObject) + if (requiresPadding) { // We are assuming that allocation of minimal object flips the alignment paddedSize += MIN_OBJECT_SIZE; + _ASSERTE(IS_ALIGNED(MIN_OBJECT_SIZE + sizeof(int32_t), sizeof(int64_t))); } else { @@ -231,7 +234,7 @@ EXTERN_C FCDECL1(Object*, RhpNewFastMisalign, MethodTable* pMT) if ((size_t)(cxt->getAllocLimit() - alloc_ptr) >= paddedSize) { cxt->setAllocPtr(alloc_ptr + paddedSize); - if (requiresAlignObject) + if (requiresPadding) { Object* dummy = (Object*)alloc_ptr; dummy->SetMethodTable(g_pFreeObjectMethodTable); From 4e765cddf13eef0e0d037772b30cc4cdff44d30e Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Tue, 21 Oct 2025 22:07:03 +0200 Subject: [PATCH 5/7] Feedback --- src/coreclr/runtime/portable/AllocFast.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/coreclr/runtime/portable/AllocFast.cpp b/src/coreclr/runtime/portable/AllocFast.cpp index 4d8397dd95d6cc..2d690de4424429 100644 --- a/src/coreclr/runtime/portable/AllocFast.cpp +++ b/src/coreclr/runtime/portable/AllocFast.cpp @@ -82,7 +82,6 @@ static Object* NewArrayFastAlign8Core(MethodTable* pMT, INT_PTR size) { // We are assuming that allocation of minimal object flips the alignment paddedSize += MIN_OBJECT_SIZE; - _ASSERTE(IS_ALIGNED(alloc_ptr + MIN_OBJECT_SIZE, sizeof(int64_t))); } _ASSERTE(alloc_ptr <= cxt->getAllocLimit()); @@ -95,6 +94,7 @@ static Object* NewArrayFastAlign8Core(MethodTable* pMT, INT_PTR size) dummy->SetMethodTable(g_pFreeObjectMethodTable); alloc_ptr += MIN_OBJECT_SIZE; } + _ASSERTE(IS_ALIGNED(alloc_ptr, sizeof(int64_t))); PtrArray* pObject = (PtrArray *)alloc_ptr; pObject->SetMethodTable(pMT); pObject->SetNumComponents((INT32)size); @@ -185,7 +185,6 @@ EXTERN_C FCDECL1(Object*, RhpNewFastAlign8, MethodTable* pMT) { // We are assuming that allocation of minimal object flips the alignment paddedSize += MIN_OBJECT_SIZE; - _ASSERTE(IS_ALIGNED(alloc_ptr + MIN_OBJECT_SIZE, sizeof(int64_t))); } _ASSERTE(alloc_ptr <= cxt->getAllocLimit()); @@ -198,6 +197,7 @@ EXTERN_C FCDECL1(Object*, RhpNewFastAlign8, MethodTable* pMT) dummy->SetMethodTable(g_pFreeObjectMethodTable); alloc_ptr += MIN_OBJECT_SIZE; } + _ASSERTE(IS_ALIGNED(alloc_ptr, sizeof(int64_t))); PtrArray* pObject = (PtrArray*)alloc_ptr; pObject->SetMethodTable(pMT); return pObject; @@ -223,11 +223,6 @@ EXTERN_C FCDECL1(Object*, RhpNewFastMisalign, MethodTable* pMT) { // We are assuming that allocation of minimal object flips the alignment paddedSize += MIN_OBJECT_SIZE; - _ASSERTE(IS_ALIGNED(MIN_OBJECT_SIZE + sizeof(int32_t), sizeof(int64_t))); - } - else - { - _ASSERTE((((uint32_t)alloc_ptr) & (sizeof(int64_t) - 1)) == sizeof(int32_t)); } _ASSERTE(alloc_ptr <= cxt->getAllocLimit()); @@ -240,6 +235,7 @@ EXTERN_C FCDECL1(Object*, RhpNewFastMisalign, MethodTable* pMT) dummy->SetMethodTable(g_pFreeObjectMethodTable); alloc_ptr += MIN_OBJECT_SIZE; } + _ASSERTE((((uint32_t)alloc_ptr) & (sizeof(int64_t) - 1)) == sizeof(int32_t)); PtrArray* pObject = (PtrArray*)alloc_ptr; pObject->SetMethodTable(pMT); return pObject; From b3a288ba3e650866c024a9be821e18ada93327d1 Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Tue, 21 Oct 2025 22:11:08 +0200 Subject: [PATCH 6/7] Feedback --- src/coreclr/runtime/portable/AllocFast.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/coreclr/runtime/portable/AllocFast.cpp b/src/coreclr/runtime/portable/AllocFast.cpp index 2d690de4424429..16fc357e40612a 100644 --- a/src/coreclr/runtime/portable/AllocFast.cpp +++ b/src/coreclr/runtime/portable/AllocFast.cpp @@ -34,7 +34,6 @@ static Object* NewArrayFastCore(MethodTable* pMT, INT_PTR size) if (size < 0 || size > INT32_MAX) { RhExceptionHandling_FailedAllocation(pMT, true /* isOverflow */); - return nullptr; } Thread* thread = GetThread(); @@ -66,7 +65,6 @@ static Object* NewArrayFastAlign8Core(MethodTable* pMT, INT_PTR size) if (size < 0 || size > INT32_MAX) { RhExceptionHandling_FailedAllocation(pMT, true /* isOverflow */); - return nullptr; } Thread* thread = GetThread(); From 42f938fdf56e393709c7c34874b418fc427b4359 Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Tue, 21 Oct 2025 22:17:38 +0200 Subject: [PATCH 7/7] Gueard the align code by FEATURE_64BIT_ALIGNMENT --- src/coreclr/runtime/portable/AllocFast.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/coreclr/runtime/portable/AllocFast.cpp b/src/coreclr/runtime/portable/AllocFast.cpp index 16fc357e40612a..83b5e3f0b4e9fa 100644 --- a/src/coreclr/runtime/portable/AllocFast.cpp +++ b/src/coreclr/runtime/portable/AllocFast.cpp @@ -166,6 +166,7 @@ EXTERN_C FCDECL1(Object*, RhpNewFast, MethodTable* pMT) return AllocateObject(pMT, 0, 0); } +#if defined(FEATURE_64BIT_ALIGNMENT) EXTERN_C FCDECL1(Object*, RhpNewFastAlign8, MethodTable* pMT) { FCALL_CONTRACT; @@ -241,6 +242,7 @@ EXTERN_C FCDECL1(Object*, RhpNewFastMisalign, MethodTable* pMT) return AllocateObject(pMT, GC_ALLOC_ALIGN8 | GC_ALLOC_ALIGN8_BIAS, 0); } +#endif // FEATURE_64BIT_ALIGNMENT #define MAX_STRING_LENGTH 0x3FFFFFDF