d6829032c59d01097d7aadf07caf845c53bc43eb
[WebKit-https.git] / Source / JavaScriptCore / heap / RegisterState.h
1 /*
2  * Copyright (C) 2017 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #pragma once
27
28 #include <setjmp.h>
29
30 namespace JSC {
31
32 #if !OS(WINDOWS) && !(OS(LINUX) && CPU(ARM64))
33
34 // ALLOCATE_AND_GET_REGISTER_STATE has to ensure that the GC sees callee-saves. It achieves this by
35 // ensuring that the callee-saves are either spilled to the stack or saved in the RegisterState. The code
36 // looks like it's achieving only the latter. However, it's possible that the compiler chooses to use
37 // a callee-save for one of the caller's variables, which means that the value that we were interested in
38 // got spilled. In that case, we will store something bogus into the RegisterState, and that's OK.
39
40 #if CPU(X86)
41 struct RegisterState {
42     uint32_t ebx;
43     uint32_t edi;
44     uint32_t esi;
45 };
46
47 #define SAVE_REG(regname, where) \
48     asm volatile ("movl %%" #regname ", %0" : "=m"(where) : : "memory")
49
50 #define ALLOCATE_AND_GET_REGISTER_STATE(registers) \
51     RegisterState registers; \
52     SAVE_REG(ebx, registers.ebx); \
53     SAVE_REG(edi, registers.edi); \
54     SAVE_REG(esi, registers.esi)
55
56 #elif CPU(X86_64)
57 struct RegisterState {
58     uint64_t rbx;
59     uint64_t r12;
60     uint64_t r13;
61     uint64_t r14;
62     uint64_t r15;
63 };
64
65 #define SAVE_REG(regname, where) \
66     asm volatile ("movq %%" #regname ", %0" : "=m"(where) : : "memory")
67
68 #define ALLOCATE_AND_GET_REGISTER_STATE(registers) \
69     RegisterState registers; \
70     SAVE_REG(rbx, registers.rbx); \
71     SAVE_REG(r12, registers.r12); \
72     SAVE_REG(r13, registers.r13); \
73     SAVE_REG(r14, registers.r14); \
74     SAVE_REG(r15, registers.r15)
75
76 #elif CPU(ARM_THUMB2)
77 struct RegisterState {
78     uint32_t r4;
79     uint32_t r5;
80     uint32_t r6;
81     uint32_t r8;
82     uint32_t r9;
83     uint32_t r10;
84     uint32_t r11;
85 };
86
87 #define SAVE_REG(regname, where) \
88     asm volatile ("str " #regname ", %0" : "=m"(where) : : "memory")
89
90 #define ALLOCATE_AND_GET_REGISTER_STATE(registers) \
91     RegisterState registers; \
92     SAVE_REG(r4, registers.r4); \
93     SAVE_REG(r5, registers.r5); \
94     SAVE_REG(r6, registers.r6); \
95     SAVE_REG(r8, registers.r8); \
96     SAVE_REG(r9, registers.r9); \
97     SAVE_REG(r10, registers.r10); \
98     SAVE_REG(r11, registers.r11)
99
100 #elif CPU(ARM64)
101 struct RegisterState {
102     uint64_t x19;
103     uint64_t x20;
104     uint64_t x21;
105     uint64_t x22;
106     uint64_t x23;
107     uint64_t x24;
108     uint64_t x25;
109     uint64_t x26;
110     uint64_t x27;
111     uint64_t x28;
112 };
113
114 #define SAVE_REG(regname, where) \
115     asm volatile ("str " #regname ", %0" : "=m"(where) : : "memory")
116
117 #define ALLOCATE_AND_GET_REGISTER_STATE(registers) \
118     RegisterState registers; \
119     SAVE_REG(x19, registers.x19); \
120     SAVE_REG(x20, registers.x20); \
121     SAVE_REG(x21, registers.x21); \
122     SAVE_REG(x22, registers.x22); \
123     SAVE_REG(x23, registers.x23); \
124     SAVE_REG(x24, registers.x24); \
125     SAVE_REG(x25, registers.x25); \
126     SAVE_REG(x26, registers.x26); \
127     SAVE_REG(x27, registers.x27); \
128     SAVE_REG(x28, registers.x28)
129
130 #endif
131 #endif // !OS(WINDOWS)
132
133 #ifndef ALLOCATE_AND_GET_REGISTER_STATE
134 #if COMPILER(GCC_OR_CLANG)
135 #define REGISTER_BUFFER_ALIGNMENT __attribute__ ((aligned (sizeof(void*))))
136 #else
137 #define REGISTER_BUFFER_ALIGNMENT
138 #endif
139
140 typedef jmp_buf RegisterState;
141
142 // ALLOCATE_AND_GET_REGISTER_STATE() is a macro so that it is always "inlined" even in debug builds.
143 #if COMPILER(MSVC)
144 #pragma warning(push)
145 #pragma warning(disable: 4611)
146 #define ALLOCATE_AND_GET_REGISTER_STATE(registers) \
147     RegisterState registers REGISTER_BUFFER_ALIGNMENT; \
148     setjmp(registers)
149 #pragma warning(pop)
150 #else
151 #define ALLOCATE_AND_GET_REGISTER_STATE(registers) \
152     RegisterState registers REGISTER_BUFFER_ALIGNMENT; \
153     setjmp(registers)
154 #endif
155 #endif // ALLOCATE_AND_GET_REGISTER_STATE
156
157 } // namespace JSC
158