Skip to content

Commit c2cb73f

Browse files
committed
Implement FEATURE_DOUBLE_ALIGNMENT_HINT for linux-x86
1 parent 458bfe7 commit c2cb73f

File tree

2 files changed

+104
-34
lines changed

2 files changed

+104
-34
lines changed

src/coreclr/pal/inc/unixasmmacros.inc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@
4343
#define GC_ALLOC_ALIGN8_BIAS 4
4444
#define GC_ALLOC_ALIGN8 8
4545

46+
#define G_FREE_OBJECT_METHOD_TABLE g_pFreeObjectMethodTable
47+
4648
#if defined(HOST_X86)
4749
#include "unixasmmacrosx86.inc"
4850
#elif defined(HOST_AMD64)

src/coreclr/runtime/i386/AllocFast.S

Lines changed: 102 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4,55 +4,108 @@
44
.intel_syntax noprefix
55
#include "AsmMacros_Shared.h"
66

7-
// Allocate non-array, non-finalizable object. If the allocation doesn't fit into the current thread's
8-
// allocation context then automatically fallback to the slow allocation path.
7+
// Shared code for RhpNewFast, RhpNewFastAlign8 and RhpNewFastMisalign
98
// ECX == MethodTable
10-
LEAF_ENTRY RhpNewFast, _TEXT
9+
.macro NEW_FAST Variation
1110

1211
// edx = ee_alloc_context pointer, TRASHES eax
1312
INLINE_GET_ALLOC_CONTEXT
1413

15-
//
16-
// ecx contains MethodTable pointer
17-
//
14+
// When doing aligned or misaligned allocation we first check
15+
// the alignment and skip to the regular path if it's already
16+
// matching the expectation.
17+
// Otherwise, we try to allocate size + ASM_MIN_OBJECT_SIZE and
18+
// then prepend a dummy free object at the beginning of the
19+
// allocation.
20+
.ifnc \Variation,
21+
mov eax, [edx + OFFSETOF__ee_alloc_context__alloc_ptr]
22+
test eax, 7
23+
.ifc \Variation,Align8
24+
jz 1f // AlreadyAligned
25+
.else // Variation == "Misalign"
26+
jnz 1f // AlreadyAligned
27+
.endif
28+
1829
mov eax, [ecx + OFFSETOF__MethodTable__m_uBaseSize]
30+
add eax, ASM_MIN_OBJECT_SIZE
31+
add eax, [edx + OFFSETOF__ee_alloc_context__alloc_ptr]
32+
cmp eax, [edx + OFFSETOF__ee_alloc_context__combined_limit]
33+
ja 2f // AllocFailed
34+
mov [edx + OFFSETOF__ee_alloc_context__alloc_ptr], eax
1935

20-
//
21-
// eax: base size
22-
// ecx: MethodTable pointer
23-
// edx: ee_alloc_context pointer
24-
//
36+
// calc the new object pointer and initialize it
37+
sub eax, [ecx + OFFSETOF__MethodTable__m_uBaseSize]
38+
mov [eax + OFFSETOF__Object__m_pEEType], ecx
39+
40+
// initialize the padding object preceeding the new object
41+
PREPARE_EXTERNAL_VAR G_FREE_OBJECT_METHOD_TABLE, edx
42+
mov [eax + OFFSETOF__Object__m_pEEType - ASM_MIN_OBJECT_SIZE], edx
43+
mov dword ptr [eax + OFFSETOF__Array__m_Length - ASM_MIN_OBJECT_SIZE], 0
44+
45+
ret
46+
.endif // Variation != ""
2547

48+
1: // AlreadyAligned
49+
mov eax, [ecx + OFFSETOF__MethodTable__m_uBaseSize]
2650
add eax, [edx + OFFSETOF__ee_alloc_context__alloc_ptr]
2751
cmp eax, [edx + OFFSETOF__ee_alloc_context__combined_limit]
28-
ja AllocFailed
29-
30-
// set the new alloc pointer
52+
ja 2f // AllocFailed
3153
mov [edx + OFFSETOF__ee_alloc_context__alloc_ptr], eax
3254

33-
// calc the new object pointer
55+
// calc the new object pointer and initialize it
3456
sub eax, [ecx + OFFSETOF__MethodTable__m_uBaseSize]
35-
36-
// set the new object's MethodTable pointer
3757
mov [eax + OFFSETOF__Object__m_pEEType], ecx
38-
ret
3958

40-
AllocFailed:
59+
ret
4160

42-
xor edx, edx // Flags
61+
2: // AllocFailed
62+
.ifc \Variation,
63+
xor edx, edx
64+
.else
65+
.ifc \Variation,Align8
66+
mov edx, GC_ALLOC_ALIGN8
67+
.else
68+
mov edx, GC_ALLOC_ALIGN8 + GC_ALLOC_ALIGN8_BIAS
69+
.endif
70+
.endif
4371
jmp RhpNewObject
4472

73+
.endm
74+
75+
// Allocate non-array, non-finalizable object. If the allocation doesn't fit into the current thread's
76+
// allocation context then automatically fallback to the slow allocation path.
77+
// ECX == MethodTable
78+
LEAF_ENTRY RhpNewFast, _TEXT
79+
NEW_FAST
4580
LEAF_END RhpNewFast, _TEXT
4681

82+
// Allocate simple object (not finalizable, array or value type) on an 8 byte boundary.
83+
// ECX == MethodTable
84+
LEAF_ENTRY RhpNewFastAlign8, _TEXT
85+
NEW_FAST Align8
86+
LEAF_END RhpNewFastAlign8, _TEXT
87+
88+
// Allocate a value type object (i.e. box it) on an 8 byte boundary + 4 (so that the value type payload
89+
// itself is 8 byte aligned).
90+
// ECX == MethodTable
91+
LEAF_ENTRY RhpNewFastMisalign, _TEXT
92+
NEW_FAST Misalign
93+
LEAF_END RhpNewFastMisalign, _TEXT
94+
4795
// Allocate non-array object with finalizer.
4896
// ECX == MethodTable
4997
LEAF_ENTRY RhpNewFinalizable, _TEXT
50-
5198
mov edx, GC_ALLOC_FINALIZE // Flags
5299
jmp RhpNewObject
53-
54100
LEAF_END RhpNewFinalizable, _TEXT
55101

102+
// Allocate non-array object with finalizer on an 8 byte boundary.
103+
// ECX == MethodTable
104+
LEAF_ENTRY RhpNewFinalizableAlign8, _TEXT
105+
mov edx, GC_ALLOC_FINALIZE + GC_ALLOC_ALIGN8 // Flags
106+
jmp RhpNewObject
107+
LEAF_END RhpNewFinalizableAlign8, _TEXT
108+
56109
// Allocate non-array object
57110
// ECX == MethodTable
58111
// EDX == alloc flags
@@ -253,21 +306,14 @@ LEAF_ENTRY RhpNewObjectArrayFast, _TEXT
253306
LEAF_END RhpNewObjectArrayFast, _TEXT
254307
#endif
255308

256-
257-
//
258-
// Object* RhpNewArray(MethodTable *pMT, INT_PTR size)
259-
//
260-
// ecx == MethodTable
261-
// edx == element count
262-
//
263-
LEAF_ENTRY RhpNewArray, _TEXT
264-
309+
// Shared code for RhpNewArray and RhpNewArrayFastAlign8
310+
.macro NEW_ARRAY Flags
265311
PUSH_COOP_PINVOKE_FRAME eax
266312

267313
// Push alloc helper arguments (transition frame, size, flags, MethodTable).
268314
push eax // transition frame
269315
push edx // numElements
270-
push 0 // Flags
316+
push \Flags // Flags
271317
push ecx // MethodTable
272318

273319
// void* RhpGcAlloc(MethodTable *pEEType, uint32_t uFlags, uintptr_t numElements, void * pTransitionFrame)
@@ -278,15 +324,37 @@ LEAF_ENTRY RhpNewArray, _TEXT
278324
POP_COOP_PINVOKE_FRAME
279325

280326
test eax, eax
281-
jz ArrayOutOfMemory
327+
jz 1f
282328

283329
ret
284330

285-
ArrayOutOfMemory:
331+
1:
286332
// This is the OOM failure path. We're going to tail-call to a managed helper that will throw
287333
// an out of memory exception that the caller of this allocator understands.
288334

289335
xor edx, edx // Indicate that we should throw OOM.
290336
jmp RhExceptionHandling_FailedAllocation
337+
.endm
291338

339+
//
340+
// Object* RhpNewArray(MethodTable *pMT, INT_PTR size)
341+
//
342+
// ecx == MethodTable
343+
// edx == element count
344+
//
345+
LEAF_ENTRY RhpNewArray, _TEXT
346+
NEW_ARRAY 0
292347
LEAF_END RhpNewArray, _TEXT
348+
349+
//
350+
// Object* RhpNewArrayFastAlign8(MethodTable *pMT, INT_PTR size)
351+
//
352+
// ecx == MethodTable
353+
// edx == element count
354+
//
355+
LEAF_ENTRY RhpNewArrayFastAlign8, _TEXT
356+
// We don't really provide a fast path here. CoreCLR has a configurable threshold
357+
// for array size to go to large object heap and it's not worth the extra effort
358+
// to check for it.
359+
NEW_ARRAY GC_ALLOC_ALIGN8
360+
LEAF_END RhpNewArrayFastAlign8, _TEXT

0 commit comments

Comments
 (0)