Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Arm64: Implement region write barriers #111636

Open
wants to merge 45 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
db6c2cf
Arm64: Implement region write barriers
a74nh Jan 16, 2025
5de7e0f
Fix byte region barriers
a74nh Jan 21, 2025
9315aa1
Fix bit region barriers
a74nh Jan 21, 2025
d0e46f0
test instead of cmp for bitwise write barriers
a74nh Jan 22, 2025
cb83f53
use LSE to atomically update bitwise write barriers
a74nh Jan 22, 2025
c615772
move atomics check into gcenv.ee.cpp
a74nh Jan 23, 2025
1c865f1
Skip ephemeral checks for regionless server GC, and refactor checks
a74nh Jan 23, 2025
15dde1b
Move ephemeral checks back
a74nh Jan 24, 2025
b5b28ce
Add GC-write-barriers.md
a74nh Jan 27, 2025
c27d516
More variables for the pseudo code
a74nh Jan 27, 2025
d014417
WRITE_BARRIER_CHECK instead of TARGET_ARM64
a74nh Jan 27, 2025
6068fb0
Add JIT_CheckedWriteBarrier and fixups to doc
a74nh Jan 28, 2025
fe0ab46
Merge main
a74nh Mar 4, 2025
a416437
Use writebarriermanager for arm64.
a74nh Jan 13, 2025
86c2576
Add the different write barrier functions
a74nh Feb 25, 2025
38bc2a1
Don't clear ephemeral values
a74nh Mar 4, 2025
5eed451
Only use offsets for inline variables
a74nh Mar 4, 2025
6b29574
Remove jitinterfaceamd64.cpp
a74nh Mar 4, 2025
e3bbf96
Don't use m_pRegionShrSrc on Arm64
a74nh Mar 4, 2025
091e265
Remove commented code
a74nh Mar 4, 2025
91eb26f
make writebarriermanager closer to original code
a74nh Mar 4, 2025
b947119
undo patchedcode.asm changes
a74nh Mar 4, 2025
580c16f
Add writebarriermanager.h
a74nh Mar 4, 2025
7993687
Update doc
a74nh Mar 5, 2025
90d889b
Replace JIT_WriteBarrier with zeroed memory
a74nh Mar 5, 2025
da7b5c0
Fix writebarrier macro labels
a74nh Mar 5, 2025
dc6d0a7
Fix JIT_WriteBarrier_PreGrow64 checks
a74nh Mar 5, 2025
6e66842
remove unused label
a74nh Mar 5, 2025
729cb77
Remove JIT_UpdateWriteBarrierState
a74nh Mar 5, 2025
e0759b8
first attempt at windows .asm
a74nh Mar 5, 2025
e026a06
remove wbs_begin
a74nh Mar 5, 2025
678f8e1
fix ifdefs for windows
a74nh Mar 7, 2025
5a156d3
Remove _TEXT
a74nh Mar 7, 2025
b318113
Fix macro arg passing on OSX
a74nh Mar 7, 2025
9312f3c
Fix patching arithmetic to work on MacOS
a74nh Mar 12, 2025
13bd03c
merge main
a74nh Mar 12, 2025
0f21673
Fixup comments in doc and assembly
a74nh Mar 13, 2025
48620bb
fix location casts for windows
a74nh Mar 13, 2025
d97e4c1
copy patching changes to windows
a74nh Mar 13, 2025
8f73468
fix location casts again
a74nh Mar 13, 2025
b5cbb9e
remove extra labels
a74nh Mar 14, 2025
4dc3f63
fix windows build
a74nh Mar 14, 2025
6ea99c0
fix patched constants on windows
a74nh Mar 14, 2025
75d2443
Fix RegionShr size on windows
a74nh Mar 19, 2025
08c3635
Merge main
a74nh Mar 19, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions docs/design/coreclr/jit/GC-write-barriers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# GC write barriers

The GC write barrier function (JIT_WriteBarrier) is generally the hottest function in CoreCLR and is written in assembly. The full pseudo code for the function is as follows:


````
JIT_WriteBarrier(Object **dst, Object *ref)
Set *dst = ref

// Shadow Heap update
ifdef WRITE_BARRIER_CHECK:
if g_GCShadow != 0:
long *shadow_dst = g_GCShadow + (dst - g_lowest_address)
// Check shadow heap location is within shadow heap
if shadow_dst < g_GCShadowEnd:
*shadow_dst = ref
atomic: wait for stores to complete
if *dst != ref:
*shadow_dst = INVALIDGCVALUE

// Update the write watch table, if it's in use
ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP:
if g_sw_ww_table != 0:
char *ww_table_dst = g_sw_ww_table + (dst>>11)
if *ww_table_dst != 0:
*ww_table_dst = 0xff

// Return if the reference is not in Gen 0
if ref < g_ephemeral_low || ref >= g_ephemeral_high:
return

// Region Checks
if g_region_to_generation_table != 0:

// Calculate region locations
char reg_loc_dst = *((dst >> g_region_shr) + g_region_to_generation_table)
char reg_loc_ref = *((ref >> g_region_shr) + g_region_to_generation_table)

// Return if the region we're storing into is Gen 0
if reg_loc_dst == 0:
return

// Check this is going from old to young
if reg_loc_dst >= reg_loc_ref:
return

// Bitwise write barriers only
if g_region_use_bitwise_write_barrier:

char *card_table_dst = (dst >> 11) + g_card_table
char dst_bit = 1 << (dst >> 8 && 7)

// Check if we need to update the card table
if *card_table_dst & dst_bit == 0:
return

// Atomically update the card table
lock: *card_table_dst |= dst_bit

goto CardBundle

// Check if we need to update the card table
char *card_table_dst = (dst >> 11) + g_card_table
if *card_table_dst == 0xff:
return

// Update the card table
*card_table_dst = 0xff

CardBundle:

// Mark the card bundle table as dirty
Ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES:
char card_bundle_dst = (dst >> 21) + g_card_bundle_table
if *card_bundle_dst != 0xff:
*card_bundle_dst = 0xff

````

The Checked Write Barrier has additional checks:

````
JIT_CheckedWriteBarrier(Object **dst, Object *ref)

// Return if the destination is not on the heap
if ref < g_lowest_address || ref >= g_highest_address:
return

return JIT_WriteBarrier(dst, ref)
````



## WritebarrierManager

On AMD64, there several different implementations of the write barrier function. Each implementation assumes different state and so can skip certain checks. The actual write barrier that is called is a copy of one of these implementations. The WritebarrierManager keeps track of which implementation is currently being used. As internal state changes, the WritebarrierManager updates the copy to the correct implementation. In practice, most of the internal state is fixed on startup, with only changes to/from use of write watch barriers changing during runtime.
3 changes: 2 additions & 1 deletion src/coreclr/vm/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -745,11 +745,11 @@ if(CLR_CMAKE_TARGET_ARCH_AMD64)
)

set(VM_SOURCES_WKS_ARCH
${ARCH_SOURCES_DIR}/jitinterfaceamd64.cpp
${ARCH_SOURCES_DIR}/profiler.cpp
exceptionhandling.cpp
gcinfodecoder.cpp
jitinterfacegen.cpp
writebarriermanager.cpp
)

set(VM_HEADERS_WKS_ARCH
Expand Down Expand Up @@ -816,6 +816,7 @@ elseif(CLR_CMAKE_TARGET_ARCH_ARM64)
set(VM_SOURCES_WKS_ARCH
${ARCH_SOURCES_DIR}/profiler.cpp
gcinfodecoder.cpp
writebarriermanager.cpp
)

if(CLR_CMAKE_HOST_UNIX)
Expand Down
22 changes: 16 additions & 6 deletions src/coreclr/vm/arm64/asmhelpers.S
Original file line number Diff line number Diff line change
Expand Up @@ -194,8 +194,9 @@ LEAF_END ThePreStubPatch, _TEXT
LEAF_ENTRY JIT_UpdateWriteBarrierState, _TEXT
PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, -16

// x0-x7, x10 will contain intended new state
// x0-x7, x10-x11, x13-x14 will contain intended new state
// x8 will preserve skipEphemeralCheck
// x9 will preserve writeableOffset
// x12 will be used for pointers

mov x8, x0
Expand Down Expand Up @@ -231,12 +232,21 @@ LOCAL_LABEL(EphemeralCheckEnabled):
PREPARE_EXTERNAL_VAR g_highest_address, x12
ldr x6, [x12]

PREPARE_EXTERNAL_VAR g_region_to_generation_table, x12
ldr x7, [x12]

PREPARE_EXTERNAL_VAR g_region_shr, x12
ldr w10, [x12]

PREPARE_EXTERNAL_VAR g_region_use_bitwise_write_barrier, x12
ldr w11, [x12]

#ifdef WRITE_BARRIER_CHECK
PREPARE_EXTERNAL_VAR g_GCShadow, x12
ldr x7, [x12]
ldr x13, [x12]

PREPARE_EXTERNAL_VAR g_GCShadowEnd, x12
ldr x10, [x12]
ldr x14, [x12]
#endif

// Update wbs state
Expand All @@ -247,12 +257,12 @@ LOCAL_LABEL(EphemeralCheckEnabled):
stp x0, x1, [x12], 16
stp x2, x3, [x12], 16
stp x4, x5, [x12], 16
str x6, [x12], 8
stp x6, x7, [x12], 16
stp w10, w11, [x12], 8
#ifdef WRITE_BARRIER_CHECK
stp x7, x10, [x12], 16
stp x13, x14, [x12], 16
#endif


EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, 16
EPILOG_RETURN
LEAF_END JIT_UpdateWriteBarrierState
Expand Down
Loading
Loading