summaryrefslogtreecommitdiff
path: root/src/vm/amd64/jithelpers_slow.S
blob: aa2e8cc06404771f7636b22cb65ae88d633e1a0e (plain)
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