1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
.intel_syntax noprefix
#include "unixasmmacros.inc"
#ifdef _DEBUG
// Version for when we're sure to be in the GC, checks whether or not the card
// needs to be updated
//
// void JIT_WriteBarrier_Debug(Object** dst, Object* src)
LEAF_ENTRY JIT_WriteBarrier_Debug, _TEXT
#ifdef WRITE_BARRIER_CHECK
// **ALSO update the shadow GC heap if that is enabled**
// Do not perform the work if g_GCShadow is 0
PREPARE_EXTERNAL_VAR g_GCShadow, rax
cmp qword ptr [rax], 0
je NoShadow
// If we end up outside of the heap don't corrupt random memory
mov r10, rdi
PREPARE_EXTERNAL_VAR g_lowest_address, r11
sub r10, [r11]
jb NoShadow
// Check that our adjusted destination is somewhere in the shadow gc
add r10, [rax]
PREPARE_EXTERNAL_VAR g_GCShadowEnd, r11
cmp r10, [r11]
ja NoShadow
// Write ref into real GC// see comment below about possibility of AV
mov [rdi], rsi
// Write ref into shadow GC
mov [r10], rsi
// 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
movabs r11, INVALIDGCVALUE
mov [r10], r11
jmp DoneShadow
// If we don't have a shadow GC we won't have done the write yet
NoShadow:
#endif
mov rax, rsi
// Do the move. It is correct to possibly take an AV here, the EH code
// figures out that this came from a WriteBarrier and correctly maps it back
// to the managed method which called the WriteBarrier (see setup in
// InitializeExceptionHandling, vm\exceptionhandling.cpp).
mov [rdi], rax
#ifdef WRITE_BARRIER_CHECK
// 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
DoneShadow:
#endif
#ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
// Update the write watch table if necessary
PREPARE_EXTERNAL_VAR g_sw_ww_enabled_for_gc_heap, r10
cmp byte ptr [r10], 0x0
je CheckCardTable_Debug
mov r10, rdi
shr r10, 0xC // SoftwareWriteWatch::AddressToTableByteIndexShift
PREPARE_EXTERNAL_VAR g_sw_ww_table, r11
add r10, qword ptr [r11]
cmp byte ptr [r10], 0x0
jne CheckCardTable_Debug
mov byte ptr [r10], 0xFF
#endif
CheckCardTable_Debug:
// See if we can just quick out
PREPARE_EXTERNAL_VAR g_ephemeral_low, r10
cmp rax, [r10]
jb Exit_Debug
PREPARE_EXTERNAL_VAR g_ephemeral_high, r10
cmp rax, [r10]
jnb Exit_Debug
// Check if we need to update the card table
// Calc pCardByte
shr rdi, 0x0B
PREPARE_EXTERNAL_VAR g_card_table, r10
mov r10, [r10]
// Check if this card is dirty
cmp byte ptr [rdi + r10], 0xFF
jne UpdateCardTable_Debug
REPRET
UpdateCardTable_Debug:
mov byte ptr [rdi + r10], 0xFF
#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES
// Shift rdi by 0x0A more to get the card bundle byte (we shifted by 0x0B already)
shr rdi, 0x0A
PREPARE_EXTERNAL_VAR g_card_bundle_table, r10
add rdi, [r10]
// Check if this bundle byte is dirty
cmp byte ptr [rdi], 0xFF
jne UpdateCardBundle_Debug
REPRET
UpdateCardBundle_Debug:
mov byte ptr [rdi], 0xFF
#endif
ret
.balign 16
Exit_Debug:
REPRET
LEAF_END_MARKED JIT_WriteBarrier_Debug, _TEXT
#endif
|