Skip to content

Commit cd7e871

Browse files
authored
[NativeAOT] Enable software writewatch and card bundles on Windows. (#77934)
* amd64 * arm64 * fix ARM64 build * import conditionally
1 parent 6a67628 commit cd7e871

File tree

8 files changed

+343
-333
lines changed

8 files changed

+343
-333
lines changed

src/coreclr/nativeaot/Runtime/CMakeLists.txt

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -204,11 +204,8 @@ include_directories(${ARCH_SOURCES_DIR})
204204

205205
add_definitions(-DFEATURE_BASICFREEZE)
206206
add_definitions(-DFEATURE_CONSERVATIVE_GC)
207-
208-
if(CLR_CMAKE_TARGET_UNIX)
209-
add_definitions(-DFEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP)
210-
add_definitions(-DFEATURE_MANUALLY_MANAGED_CARD_BUNDLES)
211-
endif()
207+
add_definitions(-DFEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP)
208+
add_definitions(-DFEATURE_MANUALLY_MANAGED_CARD_BUNDLES)
212209

213210
add_definitions(-DFEATURE_CUSTOM_IMPORTS)
214211
add_definitions(-DFEATURE_DYNAMIC_CODE)

src/coreclr/nativeaot/Runtime/amd64/AsmMacros.inc

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -406,10 +406,18 @@ EXTERN REDHAWKGCINTERFACE__STRESSGC : PROC
406406
EXTERN THREAD__HIJACKFORGCSTRESS : PROC
407407
endif ;; FEATURE_GC_STRESS
408408

409+
EXTERN RhpTrapThreads : DWORD
409410
EXTERN g_lowest_address : QWORD
410411
EXTERN g_highest_address : QWORD
411412
EXTERN g_ephemeral_low : QWORD
412413
EXTERN g_ephemeral_high : QWORD
413414
EXTERN g_card_table : QWORD
414-
EXTERN RhpTrapThreads : DWORD
415+
416+
ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES
417+
EXTERN g_card_bundle_table : QWORD
418+
endif
419+
420+
ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
421+
EXTERN g_write_watch_table : QWORD
422+
endif
415423

src/coreclr/nativeaot/Runtime/amd64/WriteBarriers.S

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -255,21 +255,20 @@ LEAF_END RhpCheckedXchg, _TEXT
255255
// On entry:
256256
// rdi: address of ref-field (assigned to)
257257
// rsi: address of the data (source)
258-
// rcx: be trashed
259258
//
260259
// On exit:
261260
// rdi, rsi are incremented by 8,
262-
// rcx: trashed
261+
// rcx, r10, r11: trashed
263262
//
264263
LEAF_ENTRY RhpByRefAssignRef, _TEXT
265264
mov rcx, [rsi]
266265
mov [rdi], rcx
267266

268267
// Check whether the writes were even into the heap. If not there's no card update required.
269268
cmp rdi, [C_VAR(g_lowest_address)]
270-
jb LOCAL_LABEL(RhpByRefAssignRef_NotInHeap)
269+
jb LOCAL_LABEL(RhpByRefAssignRef_NoBarrierRequired)
271270
cmp rdi, [C_VAR(g_highest_address)]
272-
jae LOCAL_LABEL(RhpByRefAssignRef_NotInHeap)
271+
jae LOCAL_LABEL(RhpByRefAssignRef_NoBarrierRequired)
273272

274273
// Update the shadow copy of the heap with the same value just written to the same heap. (A no-op unless
275274
// we're in a debug build and write barrier checking has been enabled).
@@ -293,9 +292,9 @@ LOCAL_LABEL(RhpByRefAssignRef_CheckCardTable):
293292
// If the reference is to an object that's not in an ephemeral generation we have no need to track it
294293
// (since the object won't be collected or moved by an ephemeral collection).
295294
cmp rcx, [C_VAR(g_ephemeral_low)]
296-
jb LOCAL_LABEL(RhpByRefAssignRef_NotInHeap)
295+
jb LOCAL_LABEL(RhpByRefAssignRef_NoBarrierRequired)
297296
cmp rcx, [C_VAR(g_ephemeral_high)]
298-
jae LOCAL_LABEL(RhpByRefAssignRef_NotInHeap)
297+
jae LOCAL_LABEL(RhpByRefAssignRef_NoBarrierRequired)
299298

300299
// move current rdi value into rcx, we need to keep rdi and eventually increment by 8
301300
mov rcx, rdi
@@ -307,7 +306,7 @@ LOCAL_LABEL(RhpByRefAssignRef_CheckCardTable):
307306
shr rcx, 0x0B
308307
mov r10, [C_VAR(g_card_table)]
309308
cmp byte ptr [rcx + r10], 0x0FF
310-
je LOCAL_LABEL(RhpByRefAssignRef_NotInHeap)
309+
je LOCAL_LABEL(RhpByRefAssignRef_NoBarrierRequired)
311310

312311
// We get here if it's necessary to update the card table.
313312
mov byte ptr [rcx + r10], 0xFF
@@ -317,12 +316,12 @@ LOCAL_LABEL(RhpByRefAssignRef_CheckCardTable):
317316
shr rcx, 0x0A
318317
add rcx, [C_VAR(g_card_bundle_table)]
319318
cmp byte ptr [rcx], 0xFF
320-
je LOCAL_LABEL(RhpByRefAssignRef_NotInHeap)
319+
je LOCAL_LABEL(RhpByRefAssignRef_NoBarrierRequired)
321320

322321
mov byte ptr [rcx], 0xFF
323322
#endif
324323

325-
LOCAL_LABEL(RhpByRefAssignRef_NotInHeap):
324+
LOCAL_LABEL(RhpByRefAssignRef_NoBarrierRequired):
326325
// Increment the pointers before leaving
327326
add rdi, 0x8
328327
add rsi, 0x8

src/coreclr/nativeaot/Runtime/amd64/WriteBarriers.asm

Lines changed: 68 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,21 @@ DEFINE_UNCHECKED_WRITE_BARRIER_CORE macro BASENAME, REFREG
100100
;; we're in a debug build and write barrier checking has been enabled).
101101
UPDATE_GC_SHADOW BASENAME, REFREG, rcx
102102

103+
ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
104+
mov r11, [g_write_watch_table]
105+
cmp r11, 0
106+
je &BASENAME&_CheckCardTable_&REFREG&
107+
108+
mov r10, rcx
109+
shr r10, 0Ch ;; SoftwareWriteWatch::AddressToTableByteIndexShift
110+
add r10, r11
111+
cmp byte ptr [r10], 0
112+
jne &BASENAME&_CheckCardTable_&REFREG&
113+
mov byte ptr [r10], 0FFh
114+
endif
115+
116+
&BASENAME&_CheckCardTable_&REFREG&:
117+
103118
;; If the reference is to an object that's not in an ephemeral generation we have no need to track it
104119
;; (since the object won't be collected or moved by an ephemeral collection).
105120
cmp REFREG, [g_ephemeral_low]
@@ -111,17 +126,25 @@ DEFINE_UNCHECKED_WRITE_BARRIER_CORE macro BASENAME, REFREG
111126
;; track this write. The location address is translated into an offset in the card table bitmap. We set
112127
;; an entire byte in the card table since it's quicker than messing around with bitmasks and we only write
113128
;; the byte if it hasn't already been done since writes are expensive and impact scaling.
114-
shr rcx, 11
115-
add rcx, [g_card_table]
129+
shr rcx, 0Bh
130+
mov r10, [g_card_table]
131+
cmp byte ptr [rcx + r10], 0FFh
132+
je &BASENAME&_NoBarrierRequired_&REFREG&
133+
134+
;; We get here if it's necessary to update the card table.
135+
mov byte ptr [rcx + r10], 0FFh
136+
137+
ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES
138+
;; Shift rcx by 0Ah more to get the card bundle byte (we shifted by 0x0B already)
139+
shr rcx, 0Ah
140+
add rcx, [g_card_bundle_table]
116141
cmp byte ptr [rcx], 0FFh
117-
jne &BASENAME&_UpdateCardTable_&REFREG&
118-
119-
&BASENAME&_NoBarrierRequired_&REFREG&:
120-
ret
142+
je &BASENAME&_NoBarrierRequired_&REFREG&
121143

122-
;; We get here if it's necessary to update the card table.
123-
&BASENAME&_UpdateCardTable_&REFREG&:
124144
mov byte ptr [rcx], 0FFh
145+
endif
146+
147+
&BASENAME&_NoBarrierRequired_&REFREG&:
125148
ret
126149

127150
endm
@@ -248,55 +271,74 @@ LEAF_END RhpCheckedXchg, _TEXT
248271
;; On entry:
249272
;; rdi: address of ref-field (assigned to)
250273
;; rsi: address of the data (source)
251-
;; rcx: be trashed
252274
;;
253275
;; On exit:
254276
;; rdi, rsi are incremented by 8,
255-
;; rcx: trashed
277+
;; rcx, r10, r11: trashed
256278
;;
257279
LEAF_ENTRY RhpByRefAssignRef, _TEXT
258280
mov rcx, [rsi]
259281
mov [rdi], rcx
260282

261283
;; Check whether the writes were even into the heap. If not there's no card update required.
262284
cmp rdi, [g_lowest_address]
263-
jb RhpByRefAssignRef_NotInHeap
285+
jb RhpByRefAssignRef_NoBarrierRequired
264286
cmp rdi, [g_highest_address]
265-
jae RhpByRefAssignRef_NotInHeap
287+
jae RhpByRefAssignRef_NoBarrierRequired
266288

267289
;; Update the shadow copy of the heap with the same value just written to the same heap. (A no-op unless
268290
;; we're in a debug build and write barrier checking has been enabled).
269291
UPDATE_GC_SHADOW BASENAME, rcx, rdi
270292

293+
ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
294+
mov r11, [g_write_watch_table]
295+
cmp r11, 0
296+
je RhpByRefAssignRef_CheckCardTable
297+
298+
mov r10, rdi
299+
shr r10, 0Ch ;; SoftwareWriteWatch::AddressToTableByteIndexShift
300+
add r10, r11
301+
cmp byte ptr [r10], 0
302+
jne RhpByRefAssignRef_CheckCardTable
303+
mov byte ptr [r10], 0FFh
304+
endif
305+
306+
RhpByRefAssignRef_CheckCardTable:
307+
271308
;; If the reference is to an object that's not in an ephemeral generation we have no need to track it
272309
;; (since the object won't be collected or moved by an ephemeral collection).
273310
cmp rcx, [g_ephemeral_low]
274-
jb RhpByRefAssignRef_NotInHeap
311+
jb RhpByRefAssignRef_NoBarrierRequired
275312
cmp rcx, [g_ephemeral_high]
276-
jae RhpByRefAssignRef_NotInHeap
313+
jae RhpByRefAssignRef_NoBarrierRequired
277314

278-
;; move current rdi value into rcx and then increment the pointers
315+
;; move current rdi value into rcx, we need to keep rdi and eventually increment by 8
279316
mov rcx, rdi
280-
add rsi, 8h
281-
add rdi, 8h
282317

283318
;; We have a location on the GC heap being updated with a reference to an ephemeral object so we must
284319
;; track this write. The location address is translated into an offset in the card table bitmap. We set
285320
;; an entire byte in the card table since it's quicker than messing around with bitmasks and we only write
286321
;; the byte if it hasn't already been done since writes are expensive and impact scaling.
287-
shr rcx, 11
288-
add rcx, [g_card_table]
289-
cmp byte ptr [rcx], 0FFh
290-
jne RhpByRefAssignRef_UpdateCardTable
291-
ret
322+
shr rcx, 0Bh
323+
mov r10, [g_card_table]
324+
cmp byte ptr [rcx + r10], 0FFh
325+
je RhpByRefAssignRef_NoBarrierRequired
292326

293327
;; We get here if it's necessary to update the card table.
294-
RhpByRefAssignRef_UpdateCardTable:
328+
mov byte ptr [rcx + r10], 0FFh
329+
330+
ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES
331+
;; Shift rcx by 0Ah more to get the card bundle byte (we shifted by 0Bh already)
332+
shr rcx, 0Ah
333+
add rcx, [g_card_bundle_table]
334+
cmp byte ptr [rcx], 0FFh
335+
je RhpByRefAssignRef_NoBarrierRequired
336+
295337
mov byte ptr [rcx], 0FFh
296-
ret
338+
endif
297339

298-
RhpByRefAssignRef_NotInHeap:
299-
; Increment the pointers before leaving
340+
RhpByRefAssignRef_NoBarrierRequired:
341+
;; Increment the pointers before leaving
300342
add rdi, 8h
301343
add rsi, 8h
302344
ret

src/coreclr/nativeaot/Runtime/arm64/AsmMacros.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,14 @@ OFFSETOF__Thread__m_alloc_context__alloc_limit equ OFFSETOF__Thread__m_rgbA
108108
EXTERN g_ephemeral_high
109109
EXTERN g_card_table
110110

111+
#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES
112+
EXTERN g_card_bundle_table
113+
#endif
114+
115+
#ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
116+
EXTERN g_write_watch_table
117+
#endif
118+
111119

112120
;; -----------------------------------------------------------------------------
113121
;; Macro used to assign an alternate name to a symbol containing characters normally disallowed in a symbol
@@ -146,6 +154,15 @@ MovInstr SETS "movk"
146154
$MovInstr $Reg, #(($ConstantLo):AND:0xffff)
147155
MEND
148156

157+
;;-----------------------------------------------------------------------------
158+
;; Macro for loading a 64bit value of a global variable into a register
159+
MACRO
160+
PREPARE_EXTERNAL_VAR_INDIRECT $Name, $Reg
161+
162+
adrp $Reg, $Name
163+
ldr $Reg, [$Reg, $Name]
164+
MEND
165+
149166
;; -----------------------------------------------------------------------------
150167
;;
151168
;; Macro to export a pointer to an address inside a stub as a 64-bit variable

0 commit comments

Comments
 (0)