caa52baaa0b726b4cd678a5a42612baa921b8114
[WebKit-https.git] / Source / JavaScriptCore / assembler / ProbeContext.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 "MacroAssembler.h"
29 #include "ProbeStack.h"
30
31 #if ENABLE(MASM_PROBE)
32
33 namespace JSC {
34 namespace Probe {
35
36 struct CPUState {
37     using RegisterID = MacroAssembler::RegisterID;
38     using SPRegisterID = MacroAssembler::SPRegisterID;
39     using FPRegisterID = MacroAssembler::FPRegisterID;
40
41     static inline const char* gprName(RegisterID id) { return MacroAssembler::gprName(id); }
42     static inline const char* sprName(SPRegisterID id) { return MacroAssembler::sprName(id); }
43     static inline const char* fprName(FPRegisterID id) { return MacroAssembler::fprName(id); }
44     inline uintptr_t& gpr(RegisterID);
45     inline uintptr_t& spr(SPRegisterID);
46     inline double& fpr(FPRegisterID);
47
48     template<typename T, typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
49     T gpr(RegisterID) const;
50     template<typename T, typename std::enable_if<std::is_pointer<T>::value>::type* = nullptr>
51     T gpr(RegisterID) const;
52     template<typename T, typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
53     T spr(SPRegisterID) const;
54     template<typename T, typename std::enable_if<std::is_pointer<T>::value>::type* = nullptr>
55     T spr(SPRegisterID) const;
56     template<typename T> T fpr(FPRegisterID) const;
57
58     void*& pc();
59     void*& fp();
60     void*& sp();
61     template<typename T> T pc() const;
62     template<typename T> T fp() const;
63     template<typename T> T sp() const;
64
65     uintptr_t gprs[MacroAssembler::numberOfRegisters()];
66     uintptr_t sprs[MacroAssembler::numberOfSPRegisters()];
67     double fprs[MacroAssembler::numberOfFPRegisters()];
68 };
69
70 inline uintptr_t& CPUState::gpr(RegisterID id)
71 {
72     ASSERT(id >= MacroAssembler::firstRegister() && id <= MacroAssembler::lastRegister());
73     return gprs[id];
74 }
75
76 inline uintptr_t& CPUState::spr(SPRegisterID id)
77 {
78     ASSERT(id >= MacroAssembler::firstSPRegister() && id <= MacroAssembler::lastSPRegister());
79     return sprs[id];
80 }
81
82 inline double& CPUState::fpr(FPRegisterID id)
83 {
84     ASSERT(id >= MacroAssembler::firstFPRegister() && id <= MacroAssembler::lastFPRegister());
85     return fprs[id];
86 }
87
88 template<typename T, typename std::enable_if<std::is_integral<T>::value>::type*>
89 T CPUState::gpr(RegisterID id) const
90 {
91     CPUState* cpu = const_cast<CPUState*>(this);
92     return static_cast<T>(cpu->gpr(id));
93 }
94
95 template<typename T, typename std::enable_if<std::is_pointer<T>::value>::type*>
96 T CPUState::gpr(RegisterID id) const
97 {
98     CPUState* cpu = const_cast<CPUState*>(this);
99     return reinterpret_cast<T>(cpu->gpr(id));
100 }
101
102 template<typename T, typename std::enable_if<std::is_integral<T>::value>::type*>
103 T CPUState::spr(SPRegisterID id) const
104 {
105     CPUState* cpu = const_cast<CPUState*>(this);
106     return static_cast<T>(cpu->spr(id));
107 }
108
109 template<typename T, typename std::enable_if<std::is_pointer<T>::value>::type*>
110 T CPUState::spr(SPRegisterID id) const
111 {
112     CPUState* cpu = const_cast<CPUState*>(this);
113     return reinterpret_cast<T>(cpu->spr(id));
114 }
115
116 template<typename T>
117 T CPUState::fpr(FPRegisterID id) const
118 {
119     CPUState* cpu = const_cast<CPUState*>(this);
120     return bitwise_cast<T>(cpu->fpr(id));
121 }
122
123 inline void*& CPUState::pc()
124 {
125 #if CPU(X86) || CPU(X86_64)
126     return *reinterpret_cast<void**>(&spr(X86Registers::eip));
127 #elif CPU(ARM64)
128     return *reinterpret_cast<void**>(&spr(ARM64Registers::pc));
129 #elif CPU(ARM_THUMB2) || CPU(ARM_TRADITIONAL)
130     return *reinterpret_cast<void**>(&gpr(ARMRegisters::pc));
131 #elif CPU(MIPS)
132     RELEASE_ASSERT_NOT_REACHED();
133 #else
134 #error "Unsupported CPU"
135 #endif
136 }
137
138 inline void*& CPUState::fp()
139 {
140 #if CPU(X86) || CPU(X86_64)
141     return *reinterpret_cast<void**>(&gpr(X86Registers::ebp));
142 #elif CPU(ARM64)
143     return *reinterpret_cast<void**>(&gpr(ARM64Registers::fp));
144 #elif CPU(ARM_THUMB2) || CPU(ARM_TRADITIONAL)
145     return *reinterpret_cast<void**>(&gpr(ARMRegisters::fp));
146 #elif CPU(MIPS)
147     return *reinterpret_cast<void**>(&gpr(MIPSRegisters::fp));
148 #else
149 #error "Unsupported CPU"
150 #endif
151 }
152
153 inline void*& CPUState::sp()
154 {
155 #if CPU(X86) || CPU(X86_64)
156     return *reinterpret_cast<void**>(&gpr(X86Registers::esp));
157 #elif CPU(ARM64)
158     return *reinterpret_cast<void**>(&gpr(ARM64Registers::sp));
159 #elif CPU(ARM_THUMB2) || CPU(ARM_TRADITIONAL)
160     return *reinterpret_cast<void**>(&gpr(ARMRegisters::sp));
161 #elif CPU(MIPS)
162     return *reinterpret_cast<void**>(&gpr(MIPSRegisters::sp));
163 #else
164 #error "Unsupported CPU"
165 #endif
166 }
167
168 template<typename T>
169 T CPUState::pc() const
170 {
171     CPUState* cpu = const_cast<CPUState*>(this);
172     return reinterpret_cast<T>(cpu->pc());
173 }
174
175 template<typename T>
176 T CPUState::fp() const
177 {
178     CPUState* cpu = const_cast<CPUState*>(this);
179     return reinterpret_cast<T>(cpu->fp());
180 }
181
182 template<typename T>
183 T CPUState::sp() const
184 {
185     CPUState* cpu = const_cast<CPUState*>(this);
186     return reinterpret_cast<T>(cpu->sp());
187 }
188
189 struct State;
190 typedef void (*StackInitializationFunction)(State*);
191
192 struct State {
193     Probe::Function probeFunction;
194     void* arg;
195     StackInitializationFunction initializeStackFunction;
196     void* initializeStackArg;
197     CPUState cpu;
198 };
199
200 class Context {
201     WTF_MAKE_FAST_ALLOCATED;
202 public:
203     using RegisterID = MacroAssembler::RegisterID;
204     using SPRegisterID = MacroAssembler::SPRegisterID;
205     using FPRegisterID = MacroAssembler::FPRegisterID;
206
207     Context(State* state)
208         : m_state(state)
209         , arg(state->arg)
210         , cpu(state->cpu)
211     { }
212
213     uintptr_t& gpr(RegisterID id) { return m_state->cpu.gpr(id); }
214     uintptr_t& spr(SPRegisterID id) { return m_state->cpu.spr(id); }
215     double& fpr(FPRegisterID id) { return m_state->cpu.fpr(id); }
216     const char* gprName(RegisterID id) { return m_state->cpu.gprName(id); }
217     const char* sprName(SPRegisterID id) { return m_state->cpu.sprName(id); }
218     const char* fprName(FPRegisterID id) { return m_state->cpu.fprName(id); }
219
220     void*& pc() { return m_state->cpu.pc(); }
221     void*& fp() { return m_state->cpu.fp(); }
222     void*& sp() { return m_state->cpu.sp(); }
223
224     template<typename T> T pc() { return m_state->cpu.pc<T>(); }
225     template<typename T> T fp() { return m_state->cpu.fp<T>(); }
226     template<typename T> T sp() { return m_state->cpu.sp<T>(); }
227
228     Stack& stack()
229     {
230         ASSERT(m_stack.isValid());
231         return m_stack;
232     };
233
234     bool hasWritesToFlush() { return m_stack.hasWritesToFlush(); }
235     Stack* releaseStack() { return new Stack(WTFMove(m_stack)); }
236
237 private:
238     State* m_state;
239 public:
240     void* arg;
241     CPUState& cpu;
242
243 private:
244     Stack m_stack;
245
246     friend JS_EXPORT_PRIVATE void* probeStateForContext(Context&); // Not for general use. This should only be for writing tests.
247 };
248
249 void executeProbe(State*);
250
251 } // namespace Probe
252 } // namespace JSC
253
254 #endif // ENABLE(MASM_PROBE)