summaryrefslogtreecommitdiff
path: root/src/vm/amd64/jithelpers_slow.S
blob: 0cd5768f355ea9307145021a379e03fb7fa2d4fb (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
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license 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
        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:
#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

        // 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, 0Bh
        PREPARE_EXTERNAL_VAR g_card_table, r10
        add     rdi, [r10]

        // Check if this card is dirty
        cmp     byte ptr [rdi], 0FFh
        jne     UpdateCardTable_Debug
        REPRET

    UpdateCardTable_Debug:
        mov     byte ptr [rdi], 0FFh
        ret

    .balign 16
    Exit_Debug:
        REPRET
LEAF_END_MARKED JIT_WriteBarrier_Debug, _TEXT
#endif