Untitled diff
195 lines
LEAF_ENTRY JIT_ByRefWriteBarrier, _TEXT
LEAF_ENTRY JIT_ByRefWriteBarrierBatch, _TEXT
LOCAL_LABEL(NextByref_ByRefWriteBarrierBatch):
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
PREPARE_EXTERNAL_VAR g_lowest_address, rax
PREPARE_EXTERNAL_VAR g_lowest_address, rax
cmp rdi, [rax]
cmp rdi, [rax]
jb LOCAL_LABEL(NotInHeap_ByRefWriteBarrier)
jb LOCAL_LABEL(NotInHeap_ByRefWriteBarrierBatch)
PREPARE_EXTERNAL_VAR g_highest_address, rax
PREPARE_EXTERNAL_VAR g_highest_address, rax
cmp rdi, [rax]
cmp rdi, [rax]
jnb LOCAL_LABEL(NotInHeap_ByRefWriteBarrier)
jnb LOCAL_LABEL(NotInHeap_ByRefWriteBarrierBatch)
#ifdef WRITE_BARRIER_CHECK
#ifdef WRITE_BARRIER_CHECK
// **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
PREPARE_EXTERNAL_VAR g_GCShadow, rax
PREPARE_EXTERNAL_VAR g_GCShadow, rax
cmp qword ptr [rax], 0
cmp qword ptr [rax], 0
je LOCAL_LABEL(NoShadow_ByRefWriteBarrier)
je LOCAL_LABEL(NoShadow_ByRefWriteBarrierBatch)
// 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
PREPARE_EXTERNAL_VAR g_lowest_address, rax
PREPARE_EXTERNAL_VAR g_lowest_address, rax
sub r10, [rax]
sub r10, [rax]
jb LOCAL_LABEL(NoShadow_ByRefWriteBarrier)
jb LOCAL_LABEL(NoShadow_ByRefWriteBarrierBatch)
// Check that our adjusted destination is somewhere in the shadow gc
// Check that our adjusted destination is somewhere in the shadow gc
PREPARE_EXTERNAL_VAR g_GCShadow, rax
PREPARE_EXTERNAL_VAR g_GCShadow, rax
add r10, [rax]
add r10, [rax]
PREPARE_EXTERNAL_VAR g_GCShadowEnd, rax
PREPARE_EXTERNAL_VAR g_GCShadowEnd, rax
cmp r10, [rax]
cmp r10, [rax]
jnb LOCAL_LABEL(NoShadow_ByRefWriteBarrier)
jnb LOCAL_LABEL(NoShadow_ByRefWriteBarrierBatch)
// 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 LOCAL_LABEL(DoneShadow_ByRefWriteBarrier)
je LOCAL_LABEL(DoneShadow_ByRefWriteBarrierBatch)
movabs r11, INVALIDGCVALUE
movabs r11, INVALIDGCVALUE
mov [r10], r11
mov [r10], r11
jmp LOCAL_LABEL(DoneShadow_ByRefWriteBarrier)
jmp LOCAL_LABEL(DoneShadow_ByRefWriteBarrierBatch)
// 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
LOCAL_LABEL(NoShadow_ByRefWriteBarrier):
LOCAL_LABEL(NoShadow_ByRefWriteBarrierBatch):
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.
LOCAL_LABEL(DoneShadow_ByRefWriteBarrier):
LOCAL_LABEL(DoneShadow_ByRefWriteBarrierBatch):
#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
PREPARE_EXTERNAL_VAR g_sw_ww_enabled_for_gc_heap, rax
PREPARE_EXTERNAL_VAR g_sw_ww_enabled_for_gc_heap, rax
cmp byte ptr [rax], 0x0
cmp byte ptr [rax], 0x0
je LOCAL_LABEL(CheckCardTable_ByRefWriteBarrier)
je LOCAL_LABEL(CheckCardTable_ByRefWriteBarrierBatch)
mov rax, rdi
mov rax, rdi
shr rax, 0xC // SoftwareWriteWatch::AddressToTableByteIndexShift
shr rax, 0xC // SoftwareWriteWatch::AddressToTableByteIndexShift
PREPARE_EXTERNAL_VAR g_sw_ww_table, r10
PREPARE_EXTERNAL_VAR g_sw_ww_table, r10
add rax, qword ptr [r10]
add rax, qword ptr [r10]
cmp byte ptr [rax], 0x0
cmp byte ptr [rax], 0x0
jne LOCAL_LABEL(CheckCardTable_ByRefWriteBarrier)
jne LOCAL_LABEL(CheckCardTable_ByRefWriteBarrierBatch)
mov byte ptr [rax], 0xFF
mov byte ptr [rax], 0xFF
#endif
#endif
LOCAL_LABEL(CheckCardTable_ByRefWriteBarrier):
LOCAL_LABEL(CheckCardTable_ByRefWriteBarrierBatch):
// See if we can just quick out
// See if we can just quick out
PREPARE_EXTERNAL_VAR g_ephemeral_low, rax
PREPARE_EXTERNAL_VAR g_ephemeral_low, rax
cmp rcx, [rax]
cmp rcx, [rax]
jb LOCAL_LABEL(Exit_ByRefWriteBarrier)
jb LOCAL_LABEL(Exit_ByRefWriteBarrierBatch)
PREPARE_EXTERNAL_VAR g_ephemeral_high, rax
PREPARE_EXTERNAL_VAR g_ephemeral_high, rax
cmp rcx, [rax]
cmp rcx, [rax]
jnb LOCAL_LABEL(Exit_ByRefWriteBarrier)
jnb LOCAL_LABEL(Exit_ByRefWriteBarrierBatch)
mov rax, rcx
mov rax, rcx
PREPARE_EXTERNAL_VAR g_region_shr, rcx
PREPARE_EXTERNAL_VAR g_region_shr, rcx
mov cl, [rcx]
mov cl, [rcx]
test cl, cl
test cl, cl
je LOCAL_LABEL(SkipCheck_ByRefWriteBarrier)
je LOCAL_LABEL(SkipCheck_ByRefWriteBarrierBatch)
// 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
PREPARE_EXTERNAL_VAR g_region_to_generation_table, r10
PREPARE_EXTERNAL_VAR g_region_to_generation_table, r10
mov r10, [r10]
mov r10, [r10]
cmp byte ptr [rax + r10], 0x82
cmp byte ptr [rax + r10], 0x82
je LOCAL_LABEL(Exit_ByRefWriteBarrier)
je LOCAL_LABEL(Exit_ByRefWriteBarrierBatch)
// 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
cmp byte ptr [rax + r10], 0
cmp byte ptr [rax + r10], 0
je LOCAL_LABEL(Exit_ByRefWriteBarrier)
je LOCAL_LABEL(Exit_ByRefWriteBarrierBatch)
LOCAL_LABEL(SkipCheck_ByRefWriteBarrier):
LOCAL_LABEL(SkipCheck_ByRefWriteBarrierBatch):
PREPARE_EXTERNAL_VAR g_card_table, r10
PREPARE_EXTERNAL_VAR g_card_table, r10
mov r10, [r10]
mov r10, [r10]
PREPARE_EXTERNAL_VAR g_region_use_bitwise_write_barrier, rax
PREPARE_EXTERNAL_VAR g_region_use_bitwise_write_barrier, rax
cmp byte ptr [rax], 0
cmp byte ptr [rax], 0
je LOCAL_LABEL(CheckCardTableByte_ByRefWriteBarrier)
je LOCAL_LABEL(CheckCardTableByte_ByRefWriteBarrierBatch)
// compute card table bit
// compute card table bit
mov ecx, edi
mov ecx, edi
mov al, 1
mov al, 1
shr ecx, 8
shr ecx, 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, 0x8
add rsi, 0x8
add rdi, 0x8
add rdi, 0x8
// Check if we need to update the card table
// Check if we need to update the card table
// Calc pCardByte
// Calc pCardByte
shr rcx, 0xB
shr rcx, 0xB
// Check if this card table bit is already set
// Check if this card table bit is already set
test byte ptr [rcx + r10], al
test byte ptr [rcx + r10], al
je LOCAL_LABEL(SetCardTableBit_ByRefWriteBarrier)
je LOCAL_LABEL(SetCardTableBit_ByRefWriteBarrierBatch)
// Check if we have more in the batch and run again
dec r8d
jne LOCAL_LABEL(NextByref_ByRefWriteBarrierBatch)
REPRET
REPRET
LOCAL_LABEL(SetCardTableBit_ByRefWriteBarrier):
LOCAL_LABEL(SetCardTableBit_ByRefWriteBarrierBatch):
lock or byte ptr [rcx + r10], al
lock or byte ptr [rcx + r10], al
jmp LOCAL_LABEL(CheckCardBundle_ByRefWriteBarrier)
jmp LOCAL_LABEL(CheckCardBundle_ByRefWriteBarrierBatch)
LOCAL_LABEL(CheckCardTableByte_ByRefWriteBarrier):
LOCAL_LABEL(CheckCardTableByte_ByRefWriteBarrierBatch):
// 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, 0x8
add rsi, 0x8
add rdi, 0x8
add rdi, 0x8
shr rcx, 0xB
shr rcx, 0xB
cmp byte ptr [rcx + r10], 0xFF
cmp byte ptr [rcx + r10], 0xFF
jne LOCAL_LABEL(SetCardTableByte_ByRefWriteBarrier)
jne LOCAL_LABEL(SetCardTableByte_ByRefWriteBarrierBatch)
// Check if we have more in the batch and run again
dec r8d
jne LOCAL_LABEL(NextByref_ByRefWriteBarrierBatch)
REPRET
REPRET
LOCAL_LABEL(SetCardTableByte_ByRefWriteBarrier):
LOCAL_LABEL(SetCardTableByte_ByRefWriteBarrierBatch):
mov byte ptr [rcx + r10], 0xFF
mov byte ptr [rcx + r10], 0xFF
LOCAL_LABEL(CheckCardBundle_ByRefWriteBarrier):
LOCAL_LABEL(CheckCardBundle_ByRefWriteBarrierBatch):
#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES
#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES
// Shift rcx by 0x0A more to get the card bundle byte (we shifted by 0x0B already)
// Shift rcx by 0x0A more to get the card bundle byte (we shifted by 0x0B already)
shr rcx, 0x0A
shr rcx, 0x0A
PREPARE_EXTERNAL_VAR g_card_bundle_table, rax
PREPARE_EXTERNAL_VAR g_card_bundle_table, rax
add rcx, [rax]
add rcx, [rax]
// Check if this bundle byte is dirty
// Check if this bundle byte is dirty
cmp byte ptr [rcx], 0xFF
cmp byte ptr [rcx], 0xFF
jne LOCAL_LABEL(UpdateCardBundle_ByRefWriteBarrier)
jne LOCAL_LABEL(UpdateCardBundle_ByRefWriteBarrierBatch)
// Check if we have more in the batch and run again
dec r8d
jne LOCAL_LABEL(NextByref_ByRefWriteBarrierBatch)
REPRET
REPRET
LOCAL_LABEL(UpdateCardBundle_ByRefWriteBarrier):
LOCAL_LABEL(UpdateCardBundle_ByRefWriteBarrierBatch):
mov byte ptr [rcx], 0xFF
mov byte ptr [rcx], 0xFF
#endif
#endif
// Check if we have more in the batch and run again
dec r8d
jne LOCAL_LABEL(NextByref_ByRefWriteBarrierBatch)
ret
ret
.balign 16
.balign 16
LOCAL_LABEL(NotInHeap_ByRefWriteBarrier):
LOCAL_LABEL(NotInHeap_ByRefWriteBarrierBatch):
// 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
LOCAL_LABEL(Exit_ByRefWriteBarrier):
// At least one write is already done, increment the pointers
add rdi, 0x8
add rsi, 0x8
dec r8d
je LOCAL_LABEL(NotInHeapExit)
// Now we can do the rest of the writes without checking the heap
LOCAL_LABEL(NextByrefUnchecked):
mov rcx, [rsi]
mov [rdi], rcx
add rdi, 0x8
add rsi, 0x8
dec r8d
jne LOCAL_LABEL(NextByrefUnchecked)
LOCAL_LABEL(NotInHeapExit):
ret
LOCAL_LABEL(Exit_ByRefWriteBarrierBatch):
// Increment the pointers before leaving
// Increment the pointers before leaving
add rdi, 0x8
add rdi, 0x8
add rsi, 0x8
add rsi, 0x8
// Check if we have more in the batch and run again
dec r8d
jne LOCAL_LABEL(NextByref_ByRefWriteBarrierBatch)
ret
ret
LEAF_END_MARKED JIT_ByRefWriteBarrier, _TEXT
LEAF_END_MARKED JIT_ByRefWriteBarrierBatch, _TEXT