Diff
checker
Text
Text
Images
Documents
Excel
Folders
Legal
Enterprise
Desktop
Pricing
Sign in
Download Diffchecker Desktop
Compare text
Find the difference between two text files
Tools
History
Real-time editor
Hide unchanged lines
Disable line wrap
Layout
Split
Unified
Diff precision
Smart
Word
Char
Syntax highlighting
Choose syntax
Ignore
Transform text
Go to first change
Edit input
Diffchecker Desktop
The most secure way to run Diffchecker. Get the Diffchecker Desktop app: your diffs never leave your computer!
Get Desktop
Untitled diff
Created
2 years ago
Diff never expires
Clear
Export
Share
Explain
0 removals
Lines
Total
Removed
Characters
Total
Removed
To continue using this feature, upgrade to
Diff
checker
Pro
View Pricing
196 lines
Copy
35 additions
Lines
Total
Added
Characters
Total
Added
To continue using this feature, upgrade to
Diff
checker
Pro
View Pricing
228 lines
Copy
Copy
Copied
Copy
Copied
LEAF_ENTRY JIT_ByRefWriteBarrier
, _TEXT
LEAF_ENTRY JIT_ByRefWriteBarrier
Batch
, _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
Copy
Copied
Copy
Copied
; 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
Copy
Copied
Copy
Copied
; 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
Copy
Copied
Copy
Copied
; 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
Copy
Copied
Copy
Copied
; 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
Copy
Copied
Copy
Copied
; 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
Copy
Copied
Copy
Copied
; Check if we have more in the batch and run again
dec r8d
jne NextByref
ret
ret
Copy
Copied
Copy
Copied
LEAF_END_MARKED JIT_ByRefWriteBarrier
, _TEXT
LEAF_END_MARKED JIT_ByRefWriteBarrier
Batch
, _TEXT
Saved diffs
Original text
Open file
LEAF_ENTRY JIT_ByRefWriteBarrier, _TEXT mov rcx, [rsi] ; If !WRITE_BARRIER_CHECK do the write first, otherwise we might have to do some ShadowGC stuff ifndef WRITE_BARRIER_CHECK ; rcx is [rsi] mov [rdi], rcx endif ; When WRITE_BARRIER_CHECK is defined _NotInHeap will write the reference ; but if it isn't then it will just return. ; ; See if this is in GCHeap cmp rdi, [g_lowest_address] jb NotInHeap cmp rdi, [g_highest_address] jnb NotInHeap ifdef WRITE_BARRIER_CHECK ; we can only trash rcx in this function so in _DEBUG we need to save ; some scratch registers. push r10 push r11 push rax ; **ALSO update the shadow GC heap if that is enabled** ; Do not perform the work if g_GCShadow is 0 cmp g_GCShadow, 0 je NoShadow ; If we end up outside of the heap don't corrupt random memory mov r10, rdi sub r10, [g_lowest_address] jb NoShadow ; Check that our adjusted destination is somewhere in the shadow gc add r10, [g_GCShadow] cmp r10, [g_GCShadowEnd] jnb NoShadow ; Write ref into real GC mov [rdi], rcx ; Write ref into shadow GC mov [r10], rcx ; Ensure that the write to the shadow heap occurs before the read from ; the GC heap so that race conditions are caught by INVALIDGCVALUE mfence ; Check that GC/ShadowGC values match mov r11, [rdi] mov rax, [r10] cmp rax, r11 je DoneShadow mov r11, INVALIDGCVALUE mov [r10], r11 jmp DoneShadow ; If we don't have a shadow GC we won't have done the write yet NoShadow: mov [rdi], rcx ; 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. ; Additionally we know for sure that we are inside the heap and therefore don't ; need to replicate the above checks. DoneShadow: pop rax pop r11 pop r10 endif ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP ; Update the write watch table if necessary cmp byte ptr [g_sw_ww_enabled_for_gc_heap], 0h je CheckCardTable mov rax, rdi shr rax, 0Ch ; SoftwareWriteWatch::AddressToTableByteIndexShift add rax, qword ptr [g_sw_ww_table] cmp byte ptr [rax], 0h jne CheckCardTable mov byte ptr [rax], 0FFh endif ; See if we can just quick out CheckCardTable: cmp rcx, [g_ephemeral_low] jb Exit cmp rcx, [g_ephemeral_high] jnb Exit ; do the following checks only if we are allowed to trash rax ; otherwise we don't have enough registers ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP mov rax, rcx mov cl, [g_region_shr] test cl, cl je SkipCheck ; check if the source is in gen 2 - then it's not an ephemeral pointer shr rax, cl add rax, [g_region_to_generation_table] cmp byte ptr [rax], 82h je Exit ; check if the destination happens to be in gen 0 mov rax, rdi shr rax, cl add rax, [g_region_to_generation_table] cmp byte ptr [rax], 0 je Exit SkipCheck: cmp [g_region_use_bitwise_write_barrier], 0 je CheckCardTableByte ; compute card table bit mov rcx, rdi mov al, 1 shr rcx, 8 and cl, 7 shl al, cl ; move current rdi value into rcx and then increment the pointers mov rcx, rdi add rsi, 8h add rdi, 8h ; Check if we need to update the card table ; Calc pCardByte shr rcx, 0Bh add rcx, [g_card_table] ; Check if this card table bit is already set test byte ptr [rcx], al je SetCardTableBit REPRET SetCardTableBit: lock or byte ptr [rcx], al jmp CheckCardBundle endif CheckCardTableByte: ; move current rdi value into rcx and then increment the pointers mov rcx, rdi add rsi, 8h add rdi, 8h ; Check if we need to update the card table ; Calc pCardByte shr rcx, 0Bh add rcx, [g_card_table] ; Check if this card is dirty cmp byte ptr [rcx], 0FFh jne UpdateCardTable REPRET UpdateCardTable: mov byte ptr [rcx], 0FFh CheckCardBundle: ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES ; check if we need to update the card bundle table ; restore destination address from rdi - rdi has been incremented by 8 already lea rcx, [rdi-8] shr rcx, 15h add rcx, [g_card_bundle_table] cmp byte ptr [rcx], 0FFh jne UpdateCardBundleTable REPRET UpdateCardBundleTable: mov byte ptr [rcx], 0FFh endif ret align 16 NotInHeap: ; 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 ; 16 byte aligned. ifdef WRITE_BARRIER_CHECK ; rcx is [rsi] mov [rdi], rcx endif Exit: ; Increment the pointers before leaving add rdi, 8h add rsi, 8h ret LEAF_END_MARKED JIT_ByRefWriteBarrier, _TEXT
Changed text
Open file
LEAF_ENTRY JIT_ByRefWriteBarrierBatch, _TEXT NextByref: mov rcx, [rsi] ; If !WRITE_BARRIER_CHECK do the write first, otherwise we might have to do some ShadowGC stuff ifndef WRITE_BARRIER_CHECK ; rcx is [rsi] mov [rdi], rcx endif ; When WRITE_BARRIER_CHECK is defined _NotInHeap will write the reference ; but if it isn't then it will just return. ; ; See if this is in GCHeap cmp rdi, [g_lowest_address] jb NotInHeap cmp rdi, [g_highest_address] jnb NotInHeap ifdef WRITE_BARRIER_CHECK ; we can only trash rcx in this function so in _DEBUG we need to save ; some scratch registers. push r10 push r11 push rax ; **ALSO update the shadow GC heap if that is enabled** ; Do not perform the work if g_GCShadow is 0 cmp g_GCShadow, 0 je NoShadow ; If we end up outside of the heap don't corrupt random memory mov r10, rdi sub r10, [g_lowest_address] jb NoShadow ; Check that our adjusted destination is somewhere in the shadow gc add r10, [g_GCShadow] cmp r10, [g_GCShadowEnd] jnb NoShadow ; Write ref into real GC mov [rdi], rcx ; Write ref into shadow GC mov [r10], rcx ; Ensure that the write to the shadow heap occurs before the read from ; the GC heap so that race conditions are caught by INVALIDGCVALUE mfence ; Check that GC/ShadowGC values match mov r11, [rdi] mov rax, [r10] cmp rax, r11 je DoneShadow mov r11, INVALIDGCVALUE mov [r10], r11 jmp DoneShadow ; If we don't have a shadow GC we won't have done the write yet NoShadow: mov [rdi], rcx ; 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. ; Additionally we know for sure that we are inside the heap and therefore don't ; need to replicate the above checks. DoneShadow: pop rax pop r11 pop r10 endif ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP ; Update the write watch table if necessary cmp byte ptr [g_sw_ww_enabled_for_gc_heap], 0h je CheckCardTable mov rax, rdi shr rax, 0Ch ; SoftwareWriteWatch::AddressToTableByteIndexShift add rax, qword ptr [g_sw_ww_table] cmp byte ptr [rax], 0h jne CheckCardTable mov byte ptr [rax], 0FFh endif ; See if we can just quick out CheckCardTable: cmp rcx, [g_ephemeral_low] jb Exit cmp rcx, [g_ephemeral_high] jnb Exit ; do the following checks only if we are allowed to trash rax ; otherwise we don't have enough registers ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP mov rax, rcx mov cl, [g_region_shr] test cl, cl je SkipCheck ; check if the source is in gen 2 - then it's not an ephemeral pointer shr rax, cl add rax, [g_region_to_generation_table] cmp byte ptr [rax], 82h je Exit ; check if the destination happens to be in gen 0 mov rax, rdi shr rax, cl add rax, [g_region_to_generation_table] cmp byte ptr [rax], 0 je Exit SkipCheck: cmp [g_region_use_bitwise_write_barrier], 0 je CheckCardTableByte ; compute card table bit mov rcx, rdi mov al, 1 shr rcx, 8 and cl, 7 shl al, cl ; move current rdi value into rcx and then increment the pointers mov rcx, rdi add rsi, 8h add rdi, 8h ; Check if we need to update the card table ; Calc pCardByte shr rcx, 0Bh add rcx, [g_card_table] ; Check if this card table bit is already set test byte ptr [rcx], al je SetCardTableBit ; Check if we have more in the batch and run again dec r8d jne NextByref REPRET SetCardTableBit: lock or byte ptr [rcx], al jmp CheckCardBundle endif CheckCardTableByte: ; move current rdi value into rcx and then increment the pointers mov rcx, rdi add rsi, 8h add rdi, 8h ; Check if we need to update the card table ; Calc pCardByte shr rcx, 0Bh add rcx, [g_card_table] ; Check if this card is dirty cmp byte ptr [rcx], 0FFh jne UpdateCardTable ; Check if we have more in the batch and run again dec r8d jne NextByref REPRET UpdateCardTable: mov byte ptr [rcx], 0FFh CheckCardBundle: ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES ; check if we need to update the card bundle table ; restore destination address from rdi - rdi has been incremented by 8 already lea rcx, [rdi-8] shr rcx, 15h add rcx, [g_card_bundle_table] cmp byte ptr [rcx], 0FFh jne UpdateCardBundleTable ; Check if we have more in the batch and run again dec r8d jne NextByref REPRET UpdateCardBundleTable: mov byte ptr [rcx], 0FFh endif ; Check if we have more in the batch and run again dec r8d jne NextByref ret align 16 NotInHeap: ; 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 ; 16 byte aligned. ifdef WRITE_BARRIER_CHECK ; rcx is [rsi] mov [rdi], rcx 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: ; Increment the pointers before leaving add rdi, 8h add rsi, 8h ; Check if we have more in the batch and run again dec r8d jne NextByref ret LEAF_END_MARKED JIT_ByRefWriteBarrierBatch, _TEXT
Find difference