Skip to content

Commit 878667d

Browse files
radekdoulikAaronRobinsonMSFTjkotas
authored
[wasm][coreclr] Implement RhpNewArrayFastAlign8 (#120690)
* [wasm][coreclr] Implement RhpNewArrayFastAlign8 Resolves #120659 * Feedback * Feedback * Apply suggestions from code review Co-authored-by: Aaron Robinson <arobins@microsoft.com> * Feedback * Apply suggestions from code review Co-authored-by: Jan Kotas <jkotas@microsoft.com> * Feedback --------- Co-authored-by: Aaron Robinson <arobins@microsoft.com> Co-authored-by: Jan Kotas <jkotas@microsoft.com>
1 parent d5c1e52 commit 878667d

File tree

3 files changed

+96
-34
lines changed

3 files changed

+96
-34
lines changed

src/coreclr/runtime/portable/AllocFast.cpp

Lines changed: 85 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,16 @@
33
//
44

55
#include <fcall.h>
6+
#include <gcinterface.h>
7+
#include <vars.hpp>
68

79
extern void RhExceptionHandling_FailedAllocation(MethodTable *pMT, bool isOverflow);
810
EXTERN_C Object* RhpGcAlloc(MethodTable* pMT, uint32_t uFlags, uintptr_t numElements, void * pTransitionFrame);
911

10-
EXTERN_C FCDECL2(Object*, RhpNewVariableSizeObject, MethodTable* pMT, INT_PTR numElements)
12+
static Object* AllocateObject(MethodTable* pMT, uint32_t uFlags, INT_PTR numElements)
1113
{
12-
Object* obj = RhpGcAlloc(pMT, 0, numElements, nullptr);
14+
FCALL_CONTRACT;
15+
Object* obj = RhpGcAlloc(pMT, uFlags, numElements, nullptr);
1316
if (obj == NULL)
1417
{
1518
RhExceptionHandling_FailedAllocation(pMT, false /* isOverflow */);
@@ -18,11 +21,21 @@ EXTERN_C FCDECL2(Object*, RhpNewVariableSizeObject, MethodTable* pMT, INT_PTR nu
1821
return obj;
1922
}
2023

21-
static Object* _RhpNewArrayFastCore(MethodTable* pMT, INT_PTR size)
24+
EXTERN_C FCDECL2(Object*, RhpNewVariableSizeObject, MethodTable* pMT, INT_PTR numElements)
25+
{
26+
WRAPPER_NO_CONTRACT;
27+
return AllocateObject(pMT, 0, numElements);
28+
}
29+
30+
static Object* NewArrayFastCore(MethodTable* pMT, INT_PTR size)
2231
{
2332
FCALL_CONTRACT;
2433
_ASSERTE(pMT != NULL);
25-
_ASSERTE(size < INT32_MAX);
34+
if (size < 0 || size > INT32_MAX)
35+
{
36+
RhExceptionHandling_FailedAllocation(pMT, true /* isOverflow */);
37+
return nullptr;
38+
}
2639

2740
Thread* thread = GetThread();
2841
ee_alloc_context* cxt = thread->GetEEAllocContext();
@@ -31,7 +44,7 @@ static Object* _RhpNewArrayFastCore(MethodTable* pMT, INT_PTR size)
3144
sizeInBytes = ALIGN_UP(sizeInBytes, sizeof(void*));
3245

3346
uint8_t* alloc_ptr = cxt->getAllocPtr();
34-
ASSERT(alloc_ptr <= cxt->getAllocLimit());
47+
_ASSERTE(alloc_ptr <= cxt->getAllocLimit());
3548
if ((size_t)(cxt->getAllocLimit() - alloc_ptr) >= sizeInBytes)
3649
{
3750
cxt->setAllocPtr(alloc_ptr + sizeInBytes);
@@ -41,9 +54,72 @@ static Object* _RhpNewArrayFastCore(MethodTable* pMT, INT_PTR size)
4154
return pObject;
4255
}
4356

44-
return RhpNewVariableSizeObject(pMT, size);
57+
return AllocateObject(pMT, 0, size);
58+
}
59+
60+
#if defined(FEATURE_64BIT_ALIGNMENT)
61+
static Object* NewArrayFastAlign8Core(MethodTable* pMT, INT_PTR size)
62+
{
63+
FCALL_CONTRACT;
64+
_ASSERTE(pMT != NULL);
65+
66+
if (size < 0 || size > INT32_MAX)
67+
{
68+
RhExceptionHandling_FailedAllocation(pMT, true /* isOverflow */);
69+
return nullptr;
70+
}
71+
72+
Thread* thread = GetThread();
73+
ee_alloc_context* cxt = thread->GetEEAllocContext();
74+
75+
size_t sizeInBytes = (size_t)pMT->GetBaseSize() + ((size_t)size * (size_t)pMT->RawGetComponentSize());
76+
sizeInBytes = ALIGN_UP(sizeInBytes, sizeof(void*));
77+
78+
uint8_t* alloc_ptr = cxt->getAllocPtr();
79+
bool requiresAlignObject = !IS_ALIGNED(alloc_ptr, sizeof(int64_t));
80+
size_t paddedSize = sizeInBytes;
81+
if (requiresAlignObject)
82+
{
83+
// We are assuming that allocation of minimal object flips the alignment
84+
paddedSize += MIN_OBJECT_SIZE;
85+
}
86+
87+
_ASSERTE(alloc_ptr <= cxt->getAllocLimit());
88+
if ((size_t)(cxt->getAllocLimit() - alloc_ptr) >= paddedSize)
89+
{
90+
cxt->setAllocPtr(alloc_ptr + paddedSize);
91+
if (requiresAlignObject)
92+
{
93+
Object* dummy = (Object*)alloc_ptr;
94+
dummy->SetMethodTable(g_pFreeObjectMethodTable);
95+
alloc_ptr += MIN_OBJECT_SIZE;
96+
}
97+
PtrArray* pObject = (PtrArray *)alloc_ptr;
98+
pObject->SetMethodTable(pMT);
99+
pObject->SetNumComponents((INT32)size);
100+
return pObject;
101+
}
102+
103+
return AllocateObject(pMT, GC_ALLOC_ALIGN8, size);
45104
}
46105

106+
EXTERN_C FCDECL2(Object*, RhpNewArrayFastAlign8, MethodTable* pMT, INT_PTR size)
107+
{
108+
FCALL_CONTRACT;
109+
_ASSERTE(pMT != NULL);
110+
111+
// if the element count is <= 0x10000, no overflow is possible because the component size is
112+
// <= 0xffff, and thus the product is <= 0xffff0000, and the base size is only ~12 bytes
113+
if (size > 0x10000)
114+
{
115+
// Overflow here should result in an OOM. Let the slow path take care of it.
116+
return AllocateObject(pMT, GC_ALLOC_ALIGN8, size);
117+
}
118+
119+
return NewArrayFastAlign8Core(pMT, size);
120+
}
121+
#endif // FEATURE_64BIT_ALIGNMENT
122+
47123
EXTERN_C FCDECL2(Object*, RhpNewArrayFast, MethodTable* pMT, INT_PTR size)
48124
{
49125
FCALL_CONTRACT;
@@ -55,11 +131,11 @@ EXTERN_C FCDECL2(Object*, RhpNewArrayFast, MethodTable* pMT, INT_PTR size)
55131
if (size > 0x10000)
56132
{
57133
// Overflow here should result in an OOM. Let the slow path take care of it.
58-
return RhpNewVariableSizeObject(pMT, size);
134+
return AllocateObject(pMT, 0, size);
59135
}
60136
#endif // !HOST_64BIT
61137

62-
return _RhpNewArrayFastCore(pMT, size);
138+
return NewArrayFastCore(pMT, size);
63139
}
64140

65141
EXTERN_C FCDECL2(Object*, RhpNewPtrArrayFast, MethodTable* pMT, INT_PTR size)
@@ -74,12 +150,6 @@ EXTERN_C FCDECL1(Object*, RhpNewFast, MethodTable* pMT)
74150
return nullptr;
75151
}
76152

77-
EXTERN_C FCDECL2(Object*, RhpNewArrayFastAlign8, MethodTable* pMT, INT_PTR size)
78-
{
79-
PORTABILITY_ASSERT("RhpNewArrayFastAlign8 is not yet implemented");
80-
return nullptr;
81-
}
82-
83153
EXTERN_C FCDECL1(Object*, RhpNewFastAlign8, MethodTable* pMT)
84154
{
85155
PORTABILITY_ASSERT("RhpNewFastAlign8 is not yet implemented");
@@ -104,5 +174,5 @@ EXTERN_C FCDECL2(Object*, RhNewString, MethodTable* pMT, INT_PTR stringLength)
104174
RhExceptionHandling_FailedAllocation(pMT, false);
105175
}
106176

107-
return _RhpNewArrayFastCore(pMT, stringLength);
177+
return NewArrayFastCore(pMT, stringLength);
108178
}

src/coreclr/vm/gchelpers.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ EXTERN_C ee_alloc_context* GetThreadEEAllocContext()
5555
// numElements - number of array elements
5656
// pTransitionBlock- transition frame to make stack crawlable
5757
// Returns a pointer to the object allocated or NULL on failure.
58-
EXTERN_C Object* RhpGcAlloc(MethodTable* pMT, GC_ALLOC_FLAGS uFlags, uintptr_t numElements, TransitionBlock* pTransitionBlock)
58+
EXTERN_C Object* RhpGcAlloc(MethodTable* pMT, GC_ALLOC_FLAGS uFlags, intptr_t numElements, TransitionBlock* pTransitionBlock)
5959
{
6060
OBJECTREF newobj = NULL;
6161

src/tests/JIT/interpreter/Interpreter.cs

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2517,16 +2517,12 @@ public static bool TestArray()
25172517
if (!ArrayUInt32(32, uint.MinValue)) return false;
25182518
if (!ArrayUInt32(32, uint.MaxValue)) return false;
25192519

2520-
// active issue https://github.com/dotnet/runtime/issues/120659
2521-
if (RuntimeInformation.ProcessArchitecture != Architecture.Wasm)
2522-
{
2523-
// // long
2524-
if (!ArrayInt64(0, 0)) return false;
2525-
if (!ArrayInt64(1, 1)) return false;
2526-
if (!ArrayInt64(32, 32)) return false;
2527-
if (!ArrayInt64(32, Int64.MinValue)) return false;
2528-
if (!ArrayInt64(32, Int64.MaxValue)) return false;
2529-
}
2520+
// long
2521+
if (!ArrayInt64(0, 0)) return false;
2522+
if (!ArrayInt64(1, 1)) return false;
2523+
if (!ArrayInt64(32, 32)) return false;
2524+
if (!ArrayInt64(32, Int64.MinValue)) return false;
2525+
if (!ArrayInt64(32, Int64.MaxValue)) return false;
25302526

25312527
// float
25322528
if (!ArrayFloat(0, 0)) return false;
@@ -2535,14 +2531,10 @@ public static bool TestArray()
25352531
if (!ArrayFloat(32, float.MinValue)) return false;
25362532
if (!ArrayFloat(32, float.MaxValue)) return false;
25372533

2538-
// active issue https://github.com/dotnet/runtime/issues/120659
2539-
if (RuntimeInformation.ProcessArchitecture != Architecture.Wasm)
2540-
{
2541-
// double
2542-
if (!ArrayDouble(0, 0)) return false;
2543-
if (!ArrayDouble(1, 1)) return false;
2544-
if (!ArrayDouble(32, 32)) return false;
2545-
}
2534+
// double
2535+
if (!ArrayDouble(0, 0)) return false;
2536+
if (!ArrayDouble(1, 1)) return false;
2537+
if (!ArrayDouble(32, 32)) return false;
25462538

25472539
// ref and value types
25482540
if (!TestObjectArray()) return false;

0 commit comments

Comments
 (0)