1
0
Fork 0
mirror of https://github.com/VSadov/Satori.git synced 2025-06-08 03:27:04 +09:00

Make ByRefWriteBarrier to use the same call convention as in standard GC for R2R compatibility. (#56)

This commit is contained in:
Vladimir Sadov 2025-06-04 21:17:45 +00:00 committed by GitHub
parent 5a8c497d68
commit eb8d99299b
Signed by: github
GPG key ID: B5690EEEBB952194
5 changed files with 183 additions and 79 deletions

View file

@ -204,12 +204,11 @@
// Registers no longer containing GC pointers after CORINFO_HELP_ASSIGN_REF and CORINFO_HELP_CHECKED_ASSIGN_REF. // Registers no longer containing GC pointers after CORINFO_HELP_ASSIGN_REF and CORINFO_HELP_CHECKED_ASSIGN_REF.
#define RBM_CALLEE_GCTRASH_WRITEBARRIER RBM_CALLEE_TRASH_NOGC #define RBM_CALLEE_GCTRASH_WRITEBARRIER RBM_CALLEE_TRASH_NOGC
// TODO: Satori make more precise?
// Registers killed by CORINFO_HELP_ASSIGN_BYREF.
#define RBM_CALLEE_TRASH_WRITEBARRIER_BYREF (RBM_RSI | RBM_RDI | RBM_CALLEE_TRASH_NOGC)
// Registers no longer containing GC pointers after CORINFO_HELP_ASSIGN_BYREF. // Registers no longer containing GC pointers after CORINFO_HELP_ASSIGN_BYREF.
#define RBM_CALLEE_GCTRASH_WRITEBARRIER_BYREF (RBM_CALLEE_TRASH_NOGC & ~(RBM_RDI | RBM_RSI)) #define RBM_CALLEE_GCTRASH_WRITEBARRIER_BYREF (RBM_RAX | RBM_RCX)
// Registers killed by CORINFO_HELP_ASSIGN_BYREF.
#define RBM_CALLEE_TRASH_WRITEBARRIER_BYREF (RBM_RSI | RBM_RDI | RBM_CALLEE_GCTRASH_WRITEBARRIER_BYREF)
// We have two register classifications // We have two register classifications
// * callee trash: aka volatile or caller saved // * callee trash: aka volatile or caller saved

View file

@ -400,7 +400,7 @@ LEAF_ENTRY RhpAssignRef, _TEXT
JustAssign: JustAssign:
ALTERNATE_ENTRY RhpAssignRefAVLocationNotHeap ALTERNATE_ENTRY RhpAssignRefAVLocationNotHeap
mov [rdi], rsi // no card marking, src is not a heap object mov [rdi], rsi // no card marking, src is not a heap object
// set rdi, rsi per contract with JIT_ByRefWriteBarrier // set rdi, rsi per contract with JIT_ByRefWriteBarrier
add rdi, 8 add rdi, 8
mov rsi, r10 mov rsi, r10
@ -515,9 +515,17 @@ ALTERNATE_ENTRY RhpAssignRefAVLocation
push rdx push rdx
push r10 push r10
// also save xmm0, in case it is used for stack clearing, as JIT_ByRefWriteBarrier should not trash xmm0
// Hopefully EscapeFn cannot corrupt other xmm regs, since there is no float math or vectorizable code in there.
sub rsp, 16
movdqu [rsp], xmm0
// void SatoriRegion::EscapeFn(SatoriObject** dst, SatoriObject* src, SatoriRegion* region) // void SatoriRegion::EscapeFn(SatoriObject** dst, SatoriObject* src, SatoriRegion* region)
call qword ptr [rdx + 8] call qword ptr [rdx + 8]
movdqu xmm0, [rsp]
add rsp, 16
pop r10 pop r10
pop rdx pop rdx
pop rsi pop rsi
@ -529,31 +537,48 @@ LEAF_END RhpAssignRef, _TEXT
// //
// RhpByRefAssignRef simulates movs instruction for object references. // RhpByRefAssignRef simulates movs instruction for object references.
// //
// On entry: // Entry:
// rdi: address of ref-field (assigned to) // RDI - address of ref-field (assigned to)
// rsi: address of the data (source) // RSI - address of the data (source)
// // Exit:
// On exit: // RCX is trashed
// rdi, rsi are incremented by 8, // RAX is trashed
// rdi, rdx, r9, r10, r11: trashed // RDI, RSI are incremented by SIZEOF(LPVOID)
//
LEAF_ENTRY RhpByRefAssignRef, _TEXT LEAF_ENTRY RhpByRefAssignRef, _TEXT
lea r10, [rsi + 8] // See if dst is in GCHeap
mov rax, [C_VAR(g_card_bundle_table)] // fetch the page byte map
mov rcx, rdi
shr rcx, 30 // dst page index
cmp byte ptr [rax + rcx], 0
jne InHeap
ALTERNATE_ENTRY RhpByRefAssignRefAVLocation1 ALTERNATE_ENTRY RhpByRefAssignRefAVLocation1
mov rcx, [rsi]
ALTERNATE_ENTRY RhpByRefAssignRefAVLocation2
mov [rdi], rcx
add rdi, 8
add rsi, 8
ret
InHeap:
// JIT_WriteBarrier may trash these registers
push rdx
push r8
push r9
push r10
push r11
// save preadjusted rsi
lea r10, [rsi + 8]
mov rsi, [rsi] mov rsi, [rsi]
// See if dst is in GCHeap call CheckedEntry
mov rax, [C_VAR(g_card_bundle_table)] // fetch the page byte map
mov r8, rdi
shr r8, 30 // dst page index
cmp byte ptr [rax + r8], 0
jne C_FUNC(CheckedEntry)
NotInHeap_RhpByRefAssignRef: pop r11
ALTERNATE_ENTRY RhpByRefAssignRefAVLocation2 pop r10
mov [rdi], rsi pop r9
add rdi, 8 pop r8
mov rsi, r10 pop rdx
ret ret
LEAF_END RhpByRefAssignRef, _TEXT LEAF_END RhpByRefAssignRef, _TEXT

View file

@ -508,17 +508,28 @@ ALTERNATE_ENTRY RhpAssignRefAVLocation
mov r9, rsp mov r9, rsp
and rsp, -16 and rsp, -16
; save rsp, rcx, rdx, r8 and have enough stack for the callee ; save rsp, rcx, rdx, r8
push r9 push r9
push rcx push rcx
push rdx push rdx
push r8 push r8
; also save xmm0, in case it is used for stack clearing, as JIT_ByRefWriteBarrier should not trash xmm0
; Hopefully EscapeFn cannot corrupt other xmm regs, since there is no float math or vectorizable code in there.
sub rsp, 16
movdqu [rsp], xmm0
; shadow space
sub rsp, 20h sub rsp, 20h
; void SatoriRegion::EscapeFn(SatoriObject** dst, SatoriObject* src, SatoriRegion* region) ; void SatoriRegion::EscapeFn(SatoriObject** dst, SatoriObject* src, SatoriRegion* region)
call qword ptr [r8 + 8] call qword ptr [r8 + 8]
add rsp, 20h add rsp, 20h
movdqu xmm0, [rsp]
add rsp, 16
pop r8 pop r8
pop rdx pop rdx
pop rcx pop rcx
@ -528,33 +539,51 @@ LEAF_END RhpAssignRef, _TEXT
;; ;;
;; RhpByRefAssignRef simulates movs instruction for object references. ;; RhpByRefAssignRef simulates movs instruction for object references.
;; ;; Entry:
;; On entry: ;; RDI - address of ref-field (assigned to)
;; rdi: address of ref-field (assigned to) ;; RSI - address of the data (source)
;; rsi: address of the data (source) ;; Exit:
;; ;; RCX is trashed
;; On exit: ;; RAX is trashed
;; rdi, rsi are incremented by 8, ;; RDI, RSI are incremented by SIZEOF(LPVOID)
;; rcx, r8, r9, r11: trashed
;;
LEAF_ENTRY RhpByRefAssignRef, _TEXT LEAF_ENTRY RhpByRefAssignRef, _TEXT
mov rcx, rdi
ALTERNATE_ENTRY RhpByRefAssignRefAVLocation1
mov rdx, [rsi]
add rdi, 8h
add rsi, 8h
; See if dst is in GCHeap ; See if dst is in GCHeap
mov rax, [g_card_bundle_table] ; fetch the page byte map mov rax, [g_card_bundle_table] ; fetch the page byte map
mov r8, rcx mov rcx, rdi
shr r8, 30 ; dst page index shr rcx, 30 ; dst page index
cmp byte ptr [rax + r8], 0 cmp byte ptr [rax + rcx], 0
jne CheckedEntry jne InHeap
NotInHeap: ALTERNATE_ENTRY RhpByRefAssignRefAVLocation1
mov rcx, [rsi]
ALTERNATE_ENTRY RhpByRefAssignRefAVLocation2 ALTERNATE_ENTRY RhpByRefAssignRefAVLocation2
mov [rcx], rdx mov [rdi], rcx
ret add rdi, 8h
add rsi, 8h
ret
InHeap:
; JIT_WriteBarrier may trash these registers
push rdx
push r8
push r9
push r10
push r11
mov rcx, rdi
mov rdx, [rsi]
add rdi, 8h
add rsi, 8h
call CheckedEntry
pop r11
pop r10
pop r9
pop r8
pop rdx
ret
LEAF_END RhpByRefAssignRef, _TEXT LEAF_END RhpByRefAssignRef, _TEXT
LEAF_ENTRY RhpCheckedLockCmpXchg, _TEXT LEAF_ENTRY RhpCheckedLockCmpXchg, _TEXT

View file

@ -443,9 +443,17 @@ LEAF_ENTRY JIT_WriteBarrier, _TEXT
push rdx push rdx
push r10 push r10
// also save xmm0, in case it is used for stack clearing, as JIT_ByRefWriteBarrier should not trash xmm0
// Hopefully EscapeFn cannot corrupt other xmm regs, since there is no float math or vectorizable code in there.
sub rsp, 16
movdqu [rsp], xmm0
// void SatoriRegion::EscapeFn(SatoriObject** dst, SatoriObject* src, SatoriRegion* region) // void SatoriRegion::EscapeFn(SatoriObject** dst, SatoriObject* src, SatoriRegion* region)
call qword ptr [rdx + 8] call qword ptr [rdx + 8]
movdqu xmm0, [rsp]
add rsp, 16
pop r10 pop r10
pop rdx pop rdx
pop rsi pop rsi
@ -460,29 +468,43 @@ LEAF_END_MARKED JIT_WriteBarrier, _TEXT
// Entry: // Entry:
// RDI - address of ref-field (assigned to) // RDI - address of ref-field (assigned to)
// RSI - address of the data (source) // RSI - address of the data (source)
// Note: RyuJIT assumes that all volatile registers can be trashed by
// the CORINFO_HELP_ASSIGN_BYREF helper (i.e. JIT_ByRefWriteBarrier)
// except RDI and RSI. This helper uses and defines RDI and RSI, so
// they remain as live GC refs or byrefs, and are not killed.
// Exit: // Exit:
// RCX is trashed
// RAX is trashed
// RDI, RSI are incremented by SIZEOF(LPVOID) // RDI, RSI are incremented by SIZEOF(LPVOID)
LEAF_ENTRY JIT_ByRefWriteBarrier, _TEXT LEAF_ENTRY JIT_ByRefWriteBarrier, _TEXT
// See if dst is in GCHeap
PREPARE_EXTERNAL_VAR g_card_bundle_table, rax // fetch the page byte map
mov rcx, rdi
shr rcx, 30 // dst page index
cmp byte ptr [rax + rcx], 0
jne InHeap
mov rcx, [rsi]
mov [rdi], rcx
add rdi, 8
add rsi, 8
ret
InHeap:
// JIT_WriteBarrier may trash these registers
push rdx
push r8
push r9
push r10
push r11
// save preadjusted rsi
lea r10, [rsi + 8] lea r10, [rsi + 8]
mov rsi, [rsi] mov rsi, [rsi]
// See if dst is in GCHeap call CheckedEntry
PREPARE_EXTERNAL_VAR g_card_bundle_table, rax // fetch the page byte map
mov rax, [rax]
mov r8, rdi pop r11
shr r8, 30 // dst page index pop r10
cmp byte ptr [rax + r8], 0 pop r9
jne C_FUNC(CheckedEntry) pop r8
pop rdx
NotInHeap_ByRefWriteBarrier:
mov [rdi], rsi
add rdi, 8
mov rsi, r10
ret ret
LEAF_END_MARKED JIT_ByRefWriteBarrier, _TEXT LEAF_END_MARKED JIT_ByRefWriteBarrier, _TEXT

View file

@ -376,17 +376,28 @@ endif
mov r9, rsp mov r9, rsp
and rsp, -16 and rsp, -16
; save rsp, rcx, rdx, r8 and have enough stack for the callee ; save rsp, rcx, rdx, r8
push r9 push r9
push rcx push rcx
push rdx push rdx
push r8 push r8
; also save xmm0, in case it is used for stack clearing, as JIT_ByRefWriteBarrier should not trash xmm0
; Hopefully EscapeFn cannot corrupt other xmm regs, since there is no float math or vectorizable code in there.
sub rsp, 16
movdqu [rsp], xmm0
; shadow space
sub rsp, 20h sub rsp, 20h
; void SatoriRegion::EscapeFn(SatoriObject** dst, SatoriObject* src, SatoriRegion* region) ; void SatoriRegion::EscapeFn(SatoriObject** dst, SatoriObject* src, SatoriRegion* region)
call qword ptr [r8 + 8] call qword ptr [r8 + 8]
add rsp, 20h add rsp, 20h
movdqu xmm0, [rsp]
add rsp, 16
pop r8 pop r8
pop rdx pop rdx
pop rcx pop rcx
@ -399,27 +410,45 @@ LEAF_END_MARKED JIT_WriteBarrier, _TEXT
; Entry: ; Entry:
; RDI - address of ref-field (assigned to) ; RDI - address of ref-field (assigned to)
; RSI - address of the data (source) ; RSI - address of the data (source)
; Note: RyuJIT assumes that all volatile registers can be trashed by
; the CORINFO_HELP_ASSIGN_BYREF helper (i.e. JIT_ByRefWriteBarrier)
; except RDI and RSI. This helper uses and defines RDI and RSI, so
; they remain as live GC refs or byrefs, and are not killed.
; Exit: ; Exit:
; RCX is trashed
; RAX is trashed
; RDI, RSI are incremented by SIZEOF(LPVOID) ; RDI, RSI are incremented by SIZEOF(LPVOID)
LEAF_ENTRY JIT_ByRefWriteBarrier, _TEXT LEAF_ENTRY JIT_ByRefWriteBarrier, _TEXT
; See if dst is in GCHeap
mov rax, [g_card_bundle_table] ; fetch the page byte map
mov rcx, rdi
shr rcx, 30 ; dst page index
cmp byte ptr [rax + rcx], 0
jne InHeap
mov rcx, [rsi]
mov [rdi], rcx
add rdi, 8h
add rsi, 8h
ret
InHeap:
; JIT_WriteBarrier may trash these registers
push rdx
push r8
push r9
push r10
push r11
mov rcx, rdi mov rcx, rdi
mov rdx, [rsi] mov rdx, [rsi]
add rdi, 8h add rdi, 8h
add rsi, 8h add rsi, 8h
; See if dst is in GCHeap call CheckedEntry
mov rax, [g_card_bundle_table] ; fetch the page byte map
mov r8, rcx
shr r8, 30 ; dst page index
cmp byte ptr [rax + r8], 0
jne CheckedEntry
NotInHeap: pop r11
mov [rcx], rdx pop r10
pop r9
pop r8
pop rdx
ret ret
LEAF_END_MARKED JIT_ByRefWriteBarrier, _TEXT LEAF_END_MARKED JIT_ByRefWriteBarrier, _TEXT