[WTF] Import std::optional reference implementation as WTF::Optional
[WebKit-https.git] / Source / JavaScriptCore / dfg / DFGSlowPathGenerator.h
1 /*
2  * Copyright (C) 2012 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 #if ENABLE(DFG_JIT)
29
30 #include "DFGCommon.h"
31 #include "DFGSilentRegisterSavePlan.h"
32 #include "DFGSpeculativeJIT.h"
33 #include <wtf/FastMalloc.h>
34
35 namespace JSC { namespace DFG {
36
37 class SlowPathGenerator {
38     WTF_MAKE_FAST_ALLOCATED;
39 public:
40     SlowPathGenerator(SpeculativeJIT* jit)
41         : m_currentNode(jit->m_currentNode)
42         , m_streamIndex(jit->m_stream->size())
43         , m_origin(jit->m_origin) 
44     {
45     }
46     virtual ~SlowPathGenerator() { }
47     void generate(SpeculativeJIT* jit)
48     {
49         m_label = jit->m_jit.label();
50         jit->m_currentNode = m_currentNode;
51         jit->m_outOfLineStreamIndex = m_streamIndex;
52         jit->m_origin = m_origin;
53         generateInternal(jit);
54         jit->m_outOfLineStreamIndex = std::nullopt;
55         if (!ASSERT_DISABLED)
56             jit->m_jit.abortWithReason(DFGSlowPathGeneratorFellThrough);
57     }
58     MacroAssembler::Label label() const { return m_label; }
59     virtual MacroAssembler::Call call() const
60     {
61         RELEASE_ASSERT_NOT_REACHED(); // By default slow path generators don't have a call.
62         return MacroAssembler::Call();
63     }
64
65     const NodeOrigin& origin() const  { return m_origin; }
66
67 protected:
68     virtual void generateInternal(SpeculativeJIT*) = 0;
69     MacroAssembler::Label m_label;
70     Node* m_currentNode;
71     unsigned m_streamIndex;
72     NodeOrigin m_origin;
73 };
74
75 template<typename JumpType>
76 class JumpingSlowPathGenerator : public SlowPathGenerator {
77 public:
78     JumpingSlowPathGenerator(JumpType from, SpeculativeJIT* jit)
79         : SlowPathGenerator(jit)
80         , m_from(from)
81         , m_to(jit->m_jit.label())
82     {
83     }
84     
85 protected:
86     void linkFrom(SpeculativeJIT* jit)
87     {
88         m_from.link(&jit->m_jit);
89     }
90     
91     void jumpTo(SpeculativeJIT* jit)
92     {
93         jit->m_jit.jump().linkTo(m_to, &jit->m_jit);
94     }
95
96     JumpType m_from;
97     MacroAssembler::Label m_to;
98 };
99
100 enum class ExceptionCheckRequirement {
101     CheckNeeded,
102     CheckNotNeeded
103 };
104
105 template<typename JumpType, typename FunctionType, typename ResultType>
106 class CallSlowPathGenerator : public JumpingSlowPathGenerator<JumpType> {
107 public:
108     CallSlowPathGenerator(
109         JumpType from, SpeculativeJIT* jit, FunctionType function,
110         SpillRegistersMode spillMode, ExceptionCheckRequirement requirement, ResultType result)
111         : JumpingSlowPathGenerator<JumpType>(from, jit)
112         , m_function(function)
113         , m_spillMode(spillMode)
114         , m_exceptionCheckRequirement(requirement)
115         , m_result(result)
116     {
117         if (m_spillMode == NeedToSpill)
118             jit->silentSpillAllRegistersImpl(false, m_plans, extractResult(result));
119     }
120     
121     MacroAssembler::Call call() const override
122     {
123         return m_call;
124     }
125     
126 protected:
127     void setUp(SpeculativeJIT* jit)
128     {
129         this->linkFrom(jit);
130         if (m_spillMode == NeedToSpill) {
131             for (unsigned i = 0; i < m_plans.size(); ++i)
132                 jit->silentSpill(m_plans[i]);
133         }
134     }
135     
136     void recordCall(MacroAssembler::Call call)
137     {
138         m_call = call;
139     }
140     
141     void tearDown(SpeculativeJIT* jit)
142     {
143         if (m_spillMode == NeedToSpill) {
144             GPRReg canTrample = SpeculativeJIT::pickCanTrample(extractResult(m_result));
145             for (unsigned i = m_plans.size(); i--;)
146                 jit->silentFill(m_plans[i], canTrample);
147         }
148         if (m_exceptionCheckRequirement == ExceptionCheckRequirement::CheckNeeded)
149             jit->m_jit.exceptionCheck();
150         this->jumpTo(jit);
151     }
152
153     FunctionType m_function;
154     SpillRegistersMode m_spillMode;
155     ExceptionCheckRequirement m_exceptionCheckRequirement;
156     ResultType m_result;
157     MacroAssembler::Call m_call;
158     Vector<SilentRegisterSavePlan, 2> m_plans;
159 };
160
161 template<typename JumpType, typename FunctionType, typename ResultType, typename... Arguments>
162 class CallResultAndArgumentsSlowPathGenerator
163     : public CallSlowPathGenerator<JumpType, FunctionType, ResultType> {
164 public:
165     CallResultAndArgumentsSlowPathGenerator(
166         JumpType from, SpeculativeJIT* jit, FunctionType function,
167         SpillRegistersMode spillMode, ExceptionCheckRequirement requirement, ResultType result, Arguments... arguments)
168         : CallSlowPathGenerator<JumpType, FunctionType, ResultType>(
169             from, jit, function, spillMode, requirement, result)
170         , m_arguments(std::forward<Arguments>(arguments)...)
171     {
172     }
173
174 protected:
175     template<size_t... ArgumentsIndex>
176     void unpackAndGenerate(SpeculativeJIT* jit, std::index_sequence<ArgumentsIndex...>)
177     {
178         this->setUp(jit);
179         this->recordCall(jit->callOperation(this->m_function, extractResult(this->m_result), std::get<ArgumentsIndex>(m_arguments)...));
180         this->tearDown(jit);
181     }
182
183     void generateInternal(SpeculativeJIT* jit) override
184     {
185         unpackAndGenerate(jit, std::make_index_sequence<std::tuple_size<std::tuple<Arguments...>>::value>());
186     }
187
188     std::tuple<Arguments...> m_arguments;
189 };
190
191 template<typename JumpType, typename FunctionType, typename ResultType, typename... Arguments>
192 inline std::unique_ptr<SlowPathGenerator> slowPathCall(
193     JumpType from, SpeculativeJIT* jit, FunctionType function,
194     SpillRegistersMode spillMode, ExceptionCheckRequirement requirement,
195     ResultType result, Arguments... arguments)
196 {
197     return std::make_unique<CallResultAndArgumentsSlowPathGenerator<JumpType, FunctionType, ResultType, Arguments...>>(
198         from, jit, function, spillMode, requirement, result, arguments...);
199 }
200
201 template<typename JumpType, typename FunctionType, typename ResultType, typename... Arguments>
202 inline std::unique_ptr<SlowPathGenerator> slowPathCall(
203     JumpType from, SpeculativeJIT* jit, FunctionType function,
204     ResultType result, Arguments... arguments)
205 {
206     return slowPathCall(
207         from, jit, function, NeedToSpill, ExceptionCheckRequirement::CheckNeeded, result, arguments...);
208 }
209
210 template<typename JumpType, typename DestinationType, typename SourceType, unsigned numberOfAssignments>
211 class AssigningSlowPathGenerator : public JumpingSlowPathGenerator<JumpType> {
212 public:
213     AssigningSlowPathGenerator(
214         JumpType from, SpeculativeJIT* jit,
215         DestinationType destination[numberOfAssignments],
216         SourceType source[numberOfAssignments])
217         : JumpingSlowPathGenerator<JumpType>(from, jit)
218     {
219         for (unsigned i = numberOfAssignments; i--;) {
220             m_destination[i] = destination[i];
221             m_source[i] = source[i];
222         }
223     }
224
225 protected:
226     void generateInternal(SpeculativeJIT* jit) override
227     {
228         this->linkFrom(jit);
229         for (unsigned i = numberOfAssignments; i--;)
230             jit->m_jit.move(m_source[i], m_destination[i]);
231         this->jumpTo(jit);
232     }
233
234 private:
235     DestinationType m_destination[numberOfAssignments];
236     SourceType m_source[numberOfAssignments];
237 };
238
239 template<typename JumpType, typename DestinationType, typename SourceType, unsigned numberOfAssignments>
240 inline std::unique_ptr<SlowPathGenerator> slowPathMove(
241     JumpType from, SpeculativeJIT* jit, SourceType source[numberOfAssignments], DestinationType destination[numberOfAssignments])
242 {
243     return std::make_unique<AssigningSlowPathGenerator<JumpType, DestinationType, SourceType, numberOfAssignments>>(
244         from, jit, destination, source);
245 }
246
247 template<typename JumpType, typename DestinationType, typename SourceType>
248 inline std::unique_ptr<SlowPathGenerator> slowPathMove(
249     JumpType from, SpeculativeJIT* jit, SourceType source, DestinationType destination)
250 {
251     SourceType sourceArray[1] = { source };
252     DestinationType destinationArray[1] = { destination };
253     return std::make_unique<AssigningSlowPathGenerator<JumpType, DestinationType, SourceType, 1>>(
254         from, jit, destinationArray, sourceArray);
255 }
256
257 template<typename JumpType, typename DestinationType, typename SourceType>
258 inline std::unique_ptr<SlowPathGenerator> slowPathMove(
259     JumpType from, SpeculativeJIT* jit, SourceType source1, DestinationType destination1, SourceType source2, DestinationType destination2)
260 {
261     SourceType sourceArray[2] = { source1, source2 };
262     DestinationType destinationArray[2] = { destination1, destination2 };
263     return std::make_unique<AssigningSlowPathGenerator<JumpType, DestinationType, SourceType, 2>>(
264         from, jit, destinationArray, sourceArray);
265 }
266
267 } } // namespace JSC::DFG
268
269 #endif // ENABLD(DFG_JIT)