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
30namespace JSC {
31
32#if !OS(WINDOWS)
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)
41struct 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)
57struct 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)
77struct 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)
101struct 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#elif CPU(MIPS)
131struct RegisterState {
132 uint32_t r16;
133 uint32_t r17;
134 uint32_t r18;
135 uint32_t r19;
136 uint32_t r20;
137 uint32_t r21;
138 uint32_t r22;
139 uint32_t r23;
140};
141
142#define SAVE_REG(regname, where) \
143 asm volatile ("sw $" #regname ", %0" : "=m"(where) : : "memory")
144
145#define ALLOCATE_AND_GET_REGISTER_STATE(registers) \
146 RegisterState registers; \
147 SAVE_REG(16, registers.r16); \
148 SAVE_REG(17, registers.r17); \
149 SAVE_REG(18, registers.r18); \
150 SAVE_REG(19, registers.r19); \
151 SAVE_REG(20, registers.r20); \
152 SAVE_REG(21, registers.r21); \
153 SAVE_REG(22, registers.r22); \
154 SAVE_REG(23, registers.r23)
155
156#endif
157#endif // !OS(WINDOWS)
158
159#ifndef ALLOCATE_AND_GET_REGISTER_STATE
160
161using RegisterState = jmp_buf;
162
163// ALLOCATE_AND_GET_REGISTER_STATE() is a macro so that it is always "inlined" even in debug builds.
164#if COMPILER(MSVC)
165#pragma warning(push)
166#pragma warning(disable: 4611)
167#endif
168#define ALLOCATE_AND_GET_REGISTER_STATE(registers) \
169 alignas(alignof(void*) > alignof(RegisterState) ? alignof(void*) : alignof(RegisterState)) RegisterState registers; \
170 setjmp(registers)
171
172#if COMPILER(MSVC)
173#pragma warning(pop)
174#endif
175#endif // ALLOCATE_AND_GET_REGISTER_STATE
176
177} // namespace JSC
178
179