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