summaryrefslogtreecommitdiff
path: root/src/vm/amd64/TlsGetters.asm
blob: 7b5a30844b57086300333de2809bced3a7e0c38b (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
; 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.

; ==++==
;

;
; ==--==
; ***********************************************************************
; File: TlsGetters.asm, see history in jithelp.asm
;
; Notes: These TlsGetters (GetAppDomain(), GetThread()) are implemented
;        in a generic fashion, but might be patched at runtime to contain
;        a much faster implementation which goes straight to the TLS for
;        the Thread* or AppDomain*. 
;
;        Note that the macro takes special care to not have these become 
;        non-unwindable after the patching has overwritten the prologue of 
;        the generic getter.
; ***********************************************************************

include AsmMacros.inc
include asmconstants.inc

; Min amount of stack space that a nested function should allocate.
MIN_SIZE equ 28h


; These generic TLS getters are used for GetThread() and GetAppDomain(), they do a little
; extra work to ensure that certain registers are preserved, those include the following 
; volatile registers
; 
;       rcx
;       rdx
;       r8
;       r9
;       r10
;       r11
;       
; The return value is in rax as usual
;
; They DO NOT save scratch flowing point registers, if you need those you need to save them.

ifdef ENABLE_GET_THREAD_GENERIC_FULL_CHECK
GetThreadGenericFullCheck equ ?GetThreadGenericFullCheck@@YAPEAVThread@@XZ
extern GetThreadGenericFullCheck:proc
endif ; ENABLE_GET_THREAD_GENERIC_FULL_CHECK

; Creates a generic TLS getter using the value from TLS slot gTLSIndex.  Set GenerateGetThread
; when using this macro to generate GetThread, as that will cause special code to be generated which
; enables additional debug-only checking, such as enforcement of EE_THREAD_NOT_REQUIRED contracts
GenerateOptimizedTLSGetter macro name, GenerateGetThread

extern g&name&TLSIndex:dword
extern __imp_TlsGetValue:qword

SIZEOF_PUSHED_ARGS equ 10h

NESTED_ENTRY Get&name&Generic, _TEXT
        push_vol_reg            r10
        push_vol_reg            r11
        alloc_stack             MIN_SIZE

        ; save argument registers in shadow space
        save_reg_postrsp        rcx, MIN_SIZE + 8h  + SIZEOF_PUSHED_ARGS
        save_reg_postrsp        rdx, MIN_SIZE + 10h + SIZEOF_PUSHED_ARGS
        save_reg_postrsp        r8,  MIN_SIZE + 18h + SIZEOF_PUSHED_ARGS
        save_reg_postrsp        r9,  MIN_SIZE + 20h + SIZEOF_PUSHED_ARGS
    END_PROLOGUE

ifdef _DEBUG
        cmp     dword ptr [g&name&TLSIndex], -1
        jnz     @F
        int     3
@@:
endif ; _DEBUG

CALL_GET_THREAD_GENERIC_FULL_CHECK=0

ifdef ENABLE_GET_THREAD_GENERIC_FULL_CHECK
if GenerateGetThread

; Generating the GetThread() tlsgetter, and GetThreadGenericFullCheck is
; defined in C (in threads.cpp).  So we'll want to delegate directly to
; GetThreadGenericFullCheck, which may choose to do additional checking, such
; as enforcing EE_THREAD_NOT_REQUIRED contracts
CALL_GET_THREAD_GENERIC_FULL_CHECK=1

endif   ; GenerateGetThread
endif   ; ENABLE_GET_THREAD_GENERIC_FULL_CHECK

if CALL_GET_THREAD_GENERIC_FULL_CHECK
        call    GetThreadGenericFullCheck
else
        ; Not generating the GetThread() tlsgetter (or there is no GetThreadGenericFullCheck
        ; to call), so do nothing special--just look up the value stored at TLS slot gTLSIndex
        mov     ecx, [g&name&TLSIndex]
        call    [__imp_TlsGetValue]
endif

        ; restore arguments from shadow space
        mov     rcx, [rsp + MIN_SIZE + 8h  + SIZEOF_PUSHED_ARGS]
        mov     rdx, [rsp + MIN_SIZE + 10h + SIZEOF_PUSHED_ARGS]
        mov     r8,  [rsp + MIN_SIZE + 18h + SIZEOF_PUSHED_ARGS]
        mov     r9,  [rsp + MIN_SIZE + 20h + SIZEOF_PUSHED_ARGS]

        ; epilog
        add     rsp, MIN_SIZE
        pop     r11
        pop     r10
        ret
NESTED_END Get&name&Generic, _TEXT

        endm    

GenerateOptimizedTLSGetter Thread, 1
GenerateOptimizedTLSGetter AppDomain, 0

        end