Untitled diff

Created Diff never expires
2 removals
Lines
Total
Removed
Words
Total
Removed
To continue using this feature, upgrade to
Diffchecker logo
Diffchecker Pro
196 lines
35 additions
Lines
Total
Added
Words
Total
Added
To continue using this feature, upgrade to
Diffchecker logo
Diffchecker Pro
228 lines
LEAF_ENTRY JIT_ByRefWriteBarrier, _TEXT
LEAF_ENTRY JIT_ByRefWriteBarrierBatch, _TEXT
NextByref:
mov rcx, [rsi]
mov rcx, [rsi]


; If !WRITE_BARRIER_CHECK do the write first, otherwise we might have to do some ShadowGC stuff
; If !WRITE_BARRIER_CHECK do the write first, otherwise we might have to do some ShadowGC stuff
ifndef WRITE_BARRIER_CHECK
ifndef WRITE_BARRIER_CHECK
; rcx is [rsi]
; rcx is [rsi]
mov [rdi], rcx
mov [rdi], rcx
endif
endif


; When WRITE_BARRIER_CHECK is defined _NotInHeap will write the reference
; When WRITE_BARRIER_CHECK is defined _NotInHeap will write the reference
; but if it isn't then it will just return.
; but if it isn't then it will just return.
;
;
; See if this is in GCHeap
; See if this is in GCHeap
cmp rdi, [g_lowest_address]
cmp rdi, [g_lowest_address]
jb NotInHeap
jb NotInHeap
cmp rdi, [g_highest_address]
cmp rdi, [g_highest_address]
jnb NotInHeap
jnb NotInHeap


ifdef WRITE_BARRIER_CHECK
ifdef WRITE_BARRIER_CHECK
; we can only trash rcx in this function so in _DEBUG we need to save
; we can only trash rcx in this function so in _DEBUG we need to save
; some scratch registers.
; some scratch registers.
push r10
push r10
push r11
push r11
push rax
push rax


; **ALSO update the shadow GC heap if that is enabled**
; **ALSO update the shadow GC heap if that is enabled**
; Do not perform the work if g_GCShadow is 0
; Do not perform the work if g_GCShadow is 0
cmp g_GCShadow, 0
cmp g_GCShadow, 0
je NoShadow
je NoShadow


; If we end up outside of the heap don't corrupt random memory
; If we end up outside of the heap don't corrupt random memory
mov r10, rdi
mov r10, rdi
sub r10, [g_lowest_address]
sub r10, [g_lowest_address]
jb NoShadow
jb NoShadow


; Check that our adjusted destination is somewhere in the shadow gc
; Check that our adjusted destination is somewhere in the shadow gc
add r10, [g_GCShadow]
add r10, [g_GCShadow]
cmp r10, [g_GCShadowEnd]
cmp r10, [g_GCShadowEnd]
jnb NoShadow
jnb NoShadow


; Write ref into real GC
; Write ref into real GC
mov [rdi], rcx
mov [rdi], rcx
; Write ref into shadow GC
; Write ref into shadow GC
mov [r10], rcx
mov [r10], rcx


; Ensure that the write to the shadow heap occurs before the read from
; Ensure that the write to the shadow heap occurs before the read from
; the GC heap so that race conditions are caught by INVALIDGCVALUE
; the GC heap so that race conditions are caught by INVALIDGCVALUE
mfence
mfence


; Check that GC/ShadowGC values match
; Check that GC/ShadowGC values match
mov r11, [rdi]
mov r11, [rdi]
mov rax, [r10]
mov rax, [r10]
cmp rax, r11
cmp rax, r11
je DoneShadow
je DoneShadow
mov r11, INVALIDGCVALUE
mov r11, INVALIDGCVALUE
mov [r10], r11
mov [r10], r11


jmp DoneShadow
jmp DoneShadow


; If we don't have a shadow GC we won't have done the write yet
; If we don't have a shadow GC we won't have done the write yet
NoShadow:
NoShadow:
mov [rdi], rcx
mov [rdi], rcx


; If we had a shadow GC then we already wrote to the real GC at the same time
; If we had a shadow GC then we already wrote to the real GC at the same time
; as the shadow GC so we want to jump over the real write immediately above.
; as the shadow GC so we want to jump over the real write immediately above.
; Additionally we know for sure that we are inside the heap and therefore don't
; Additionally we know for sure that we are inside the heap and therefore don't
; need to replicate the above checks.
; need to replicate the above checks.
DoneShadow:
DoneShadow:
pop rax
pop rax
pop r11
pop r11
pop r10
pop r10
endif
endif


ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
; Update the write watch table if necessary
; Update the write watch table if necessary
cmp byte ptr [g_sw_ww_enabled_for_gc_heap], 0h
cmp byte ptr [g_sw_ww_enabled_for_gc_heap], 0h
je CheckCardTable
je CheckCardTable
mov rax, rdi
mov rax, rdi
shr rax, 0Ch ; SoftwareWriteWatch::AddressToTableByteIndexShift
shr rax, 0Ch ; SoftwareWriteWatch::AddressToTableByteIndexShift
add rax, qword ptr [g_sw_ww_table]
add rax, qword ptr [g_sw_ww_table]
cmp byte ptr [rax], 0h
cmp byte ptr [rax], 0h
jne CheckCardTable
jne CheckCardTable
mov byte ptr [rax], 0FFh
mov byte ptr [rax], 0FFh
endif
endif


; See if we can just quick out
; See if we can just quick out
CheckCardTable:
CheckCardTable:
cmp rcx, [g_ephemeral_low]
cmp rcx, [g_ephemeral_low]
jb Exit
jb Exit
cmp rcx, [g_ephemeral_high]
cmp rcx, [g_ephemeral_high]
jnb Exit
jnb Exit


; do the following checks only if we are allowed to trash rax
; do the following checks only if we are allowed to trash rax
; otherwise we don't have enough registers
; otherwise we don't have enough registers
ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
mov rax, rcx
mov rax, rcx


mov cl, [g_region_shr]
mov cl, [g_region_shr]
test cl, cl
test cl, cl
je SkipCheck
je SkipCheck


; check if the source is in gen 2 - then it's not an ephemeral pointer
; check if the source is in gen 2 - then it's not an ephemeral pointer
shr rax, cl
shr rax, cl
add rax, [g_region_to_generation_table]
add rax, [g_region_to_generation_table]
cmp byte ptr [rax], 82h
cmp byte ptr [rax], 82h
je Exit
je Exit


; check if the destination happens to be in gen 0
; check if the destination happens to be in gen 0
mov rax, rdi
mov rax, rdi
shr rax, cl
shr rax, cl
add rax, [g_region_to_generation_table]
add rax, [g_region_to_generation_table]
cmp byte ptr [rax], 0
cmp byte ptr [rax], 0
je Exit
je Exit
SkipCheck:
SkipCheck:


cmp [g_region_use_bitwise_write_barrier], 0
cmp [g_region_use_bitwise_write_barrier], 0
je CheckCardTableByte
je CheckCardTableByte


; compute card table bit
; compute card table bit
mov rcx, rdi
mov rcx, rdi
mov al, 1
mov al, 1
shr rcx, 8
shr rcx, 8
and cl, 7
and cl, 7
shl al, cl
shl al, cl


; move current rdi value into rcx and then increment the pointers
; move current rdi value into rcx and then increment the pointers
mov rcx, rdi
mov rcx, rdi
add rsi, 8h
add rsi, 8h
add rdi, 8h
add rdi, 8h


; Check if we need to update the card table
; Check if we need to update the card table
; Calc pCardByte
; Calc pCardByte
shr rcx, 0Bh
shr rcx, 0Bh
add rcx, [g_card_table]
add rcx, [g_card_table]


; Check if this card table bit is already set
; Check if this card table bit is already set
test byte ptr [rcx], al
test byte ptr [rcx], al
je SetCardTableBit
je SetCardTableBit
; Check if we have more in the batch and run again
dec r8d
jne NextByref
REPRET
REPRET


SetCardTableBit:
SetCardTableBit:
lock or byte ptr [rcx], al
lock or byte ptr [rcx], al
jmp CheckCardBundle
jmp CheckCardBundle
endif
endif
CheckCardTableByte:
CheckCardTableByte:


; move current rdi value into rcx and then increment the pointers
; move current rdi value into rcx and then increment the pointers
mov rcx, rdi
mov rcx, rdi
add rsi, 8h
add rsi, 8h
add rdi, 8h
add rdi, 8h


; Check if we need to update the card table
; Check if we need to update the card table
; Calc pCardByte
; Calc pCardByte
shr rcx, 0Bh
shr rcx, 0Bh
add rcx, [g_card_table]
add rcx, [g_card_table]


; Check if this card is dirty
; Check if this card is dirty
cmp byte ptr [rcx], 0FFh
cmp byte ptr [rcx], 0FFh
jne UpdateCardTable
jne UpdateCardTable
; Check if we have more in the batch and run again
dec r8d
jne NextByref
REPRET
REPRET


UpdateCardTable:
UpdateCardTable:
mov byte ptr [rcx], 0FFh
mov byte ptr [rcx], 0FFh


CheckCardBundle:
CheckCardBundle:


ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES
ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES
; check if we need to update the card bundle table
; check if we need to update the card bundle table
; restore destination address from rdi - rdi has been incremented by 8 already
; restore destination address from rdi - rdi has been incremented by 8 already
lea rcx, [rdi-8]
lea rcx, [rdi-8]
shr rcx, 15h
shr rcx, 15h
add rcx, [g_card_bundle_table]
add rcx, [g_card_bundle_table]
cmp byte ptr [rcx], 0FFh
cmp byte ptr [rcx], 0FFh
jne UpdateCardBundleTable
jne UpdateCardBundleTable
; Check if we have more in the batch and run again
dec r8d
jne NextByref
REPRET
REPRET


UpdateCardBundleTable:
UpdateCardBundleTable:
mov byte ptr [rcx], 0FFh
mov byte ptr [rcx], 0FFh
endif
endif
; Check if we have more in the batch and run again
dec r8d
jne NextByref
ret
ret


align 16
align 16
NotInHeap:
NotInHeap:
; If WRITE_BARRIER_CHECK then we won't have already done the mov and should do it here
; If WRITE_BARRIER_CHECK then we won't have already done the mov and should do it here
; If !WRITE_BARRIER_CHECK we want _NotInHeap and _Leave to be the same and have both
; If !WRITE_BARRIER_CHECK we want _NotInHeap and _Leave to be the same and have both
; 16 byte aligned.
; 16 byte aligned.
ifdef WRITE_BARRIER_CHECK
ifdef WRITE_BARRIER_CHECK
; rcx is [rsi]
; rcx is [rsi]
mov [rdi], rcx
mov [rdi], rcx
endif
endif
; At least one write is already done, increment the pointers
add rdi, 8h
add rsi, 8h
dec r8d
je NotInHeapExit
; Now we can do the rest of the writes without checking the heap
NextByrefUnchecked:
mov rcx, [rsi]
mov [rdi], rcx
add rdi, 8h
add rsi, 8h
dec r8d
jne NextByrefUnchecked
NotInHeapExit:
ret

Exit:
Exit:
; Increment the pointers before leaving
; Increment the pointers before leaving
add rdi, 8h
add rdi, 8h
add rsi, 8h
add rsi, 8h
; Check if we have more in the batch and run again
dec r8d
jne NextByref
ret
ret
LEAF_END_MARKED JIT_ByRefWriteBarrier, _TEXT
LEAF_END_MARKED JIT_ByRefWriteBarrierBatch, _TEXT