337c3c92cd7356e1d7919d4be43a303a3490b37f
[WebKit.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 #ifndef DFGSlowPathGenerator_h
27 #define DFGSlowPathGenerator_h
28
29 #if ENABLE(DFG_JIT)
30
31 #include "DFGCommon.h"
32 #include "DFGSilentRegisterSavePlan.h"
33 #include "DFGSpeculativeJIT.h"
34 #include <wtf/FastMalloc.h>
35
36 namespace JSC { namespace DFG {
37
38 class SlowPathGenerator {
39     WTF_MAKE_FAST_ALLOCATED;
40 public:
41     SlowPathGenerator(SpeculativeJIT* jit)
42         : m_currentNode(jit->m_currentNode)
43         , m_streamIndex(jit->m_stream->size())
44         , m_origin(jit->m_origin) 
45     {
46     }
47     virtual ~SlowPathGenerator() { }
48     void generate(SpeculativeJIT* jit)
49     {
50         m_label = jit->m_jit.label();
51         jit->m_currentNode = m_currentNode;
52         jit->m_outOfLineStreamIndex = m_streamIndex;
53         jit->m_origin = m_origin;
54         generateInternal(jit);
55         jit->m_outOfLineStreamIndex = UINT_MAX;
56         if (!ASSERT_DISABLED)
57             jit->m_jit.abortWithReason(DFGSlowPathGeneratorFellThrough);
58     }
59     MacroAssembler::Label label() const { return m_label; }
60     virtual MacroAssembler::Call call() const
61     {
62         RELEASE_ASSERT_NOT_REACHED(); // By default slow path generators don't have a call.
63         return MacroAssembler::Call();
64     }
65
66     const NodeOrigin& origin() const  { return m_origin; }
67
68 protected:
69     virtual void generateInternal(SpeculativeJIT*) = 0;
70     MacroAssembler::Label m_label;
71     Node* m_currentNode;
72     unsigned m_streamIndex;
73     NodeOrigin m_origin;
74 };
75
76 template<typename JumpType>
77 class JumpingSlowPathGenerator : public SlowPathGenerator {
78 public:
79     JumpingSlowPathGenerator(JumpType from, SpeculativeJIT* jit)
80         : SlowPathGenerator(jit)
81         , m_from(from)
82         , m_to(jit->m_jit.label())
83     {
84     }
85     
86 protected:
87     void linkFrom(SpeculativeJIT* jit)
88     {
89         m_from.link(&jit->m_jit);
90     }
91     
92     void jumpTo(SpeculativeJIT* jit)
93     {
94         jit->m_jit.jump().linkTo(m_to, &jit->m_jit);
95     }
96
97     JumpType m_from;
98     MacroAssembler::Label m_to;
99 };
100
101 enum class ExceptionCheckRequirement {
102     CheckNeeded,
103     CheckNotNeeded
104 };
105
106 template<typename JumpType, typename FunctionType, typename ResultType>
107 class CallSlowPathGenerator : public JumpingSlowPathGenerator<JumpType> {
108 public:
109     CallSlowPathGenerator(
110         JumpType from, SpeculativeJIT* jit, FunctionType function,
111         SpillRegistersMode spillMode, ExceptionCheckRequirement requirement, ResultType result)
112         : JumpingSlowPathGenerator<JumpType>(from, jit)
113         , m_function(function)
114         , m_spillMode(spillMode)
115         , m_exceptionCheckRequirement(requirement)
116         , m_result(result)
117     {
118         if (m_spillMode == NeedToSpill)
119             jit->silentSpillAllRegistersImpl(false, m_plans, extractResult(result));
120     }
121     
122     MacroAssembler::Call call() const override
123     {
124         return m_call;
125     }
126     
127 protected:
128     void setUp(SpeculativeJIT* jit)
129     {
130         this->linkFrom(jit);
131         if (m_spillMode == NeedToSpill) {
132             for (unsigned i = 0; i < m_plans.size(); ++i)
133                 jit->silentSpill(m_plans[i]);
134         }
135     }
136     
137     void recordCall(MacroAssembler::Call call)
138     {
139         m_call = call;
140     }
141     
142     void tearDown(SpeculativeJIT* jit)
143     {
144         if (m_spillMode == NeedToSpill) {
145             GPRReg canTrample = SpeculativeJIT::pickCanTrample(extractResult(m_result));
146             for (unsigned i = m_plans.size(); i--;)
147                 jit->silentFill(m_plans[i], canTrample);
148         }
149         if (m_exceptionCheckRequirement == ExceptionCheckRequirement::CheckNeeded)
150             jit->m_jit.exceptionCheck();
151         this->jumpTo(jit);
152     }
153
154     FunctionType m_function;
155     SpillRegistersMode m_spillMode;
156     ExceptionCheckRequirement m_exceptionCheckRequirement;
157     ResultType m_result;
158     MacroAssembler::Call m_call;
159     Vector<SilentRegisterSavePlan, 2> m_plans;
160 };
161
162 template<typename JumpType, typename FunctionType, typename ResultType>
163 class CallResultAndNoArgumentsSlowPathGenerator
164     : public CallSlowPathGenerator<JumpType, FunctionType, ResultType> {
165 public:
166     CallResultAndNoArgumentsSlowPathGenerator(
167         JumpType from, SpeculativeJIT* jit, FunctionType function,
168         SpillRegistersMode spillMode, ExceptionCheckRequirement requirement, ResultType result)
169         : CallSlowPathGenerator<JumpType, FunctionType, ResultType>(
170             from, jit, function, spillMode, requirement, result)
171     {
172     }
173     
174 protected:
175     void generateInternal(SpeculativeJIT* jit) override
176     {
177         this->setUp(jit);
178         this->recordCall(jit->callOperation(this->m_function, extractResult(this->m_result)));
179         this->tearDown(jit);
180     }
181 };
182
183 template<
184     typename JumpType, typename FunctionType, typename ResultType,
185     typename ArgumentType1>
186 class CallResultAndOneArgumentSlowPathGenerator
187     : public CallSlowPathGenerator<JumpType, FunctionType, ResultType> {
188 public:
189     CallResultAndOneArgumentSlowPathGenerator(
190         JumpType from, SpeculativeJIT* jit, FunctionType function,
191         SpillRegistersMode spillMode, ExceptionCheckRequirement requirement, ResultType result, ArgumentType1 argument1)
192         : CallSlowPathGenerator<JumpType, FunctionType, ResultType>(
193             from, jit, function, spillMode, requirement, result)
194         , m_argument1(argument1)
195     {
196     }
197     
198 protected:
199     void generateInternal(SpeculativeJIT* jit) override
200     {
201         this->setUp(jit);
202         this->recordCall(jit->callOperation(this->m_function, extractResult(this->m_result), m_argument1));
203         this->tearDown(jit);
204     }
205
206     ArgumentType1 m_argument1;
207 };
208
209 template<
210     typename JumpType, typename FunctionType, typename ResultType,
211     typename ArgumentType1, typename ArgumentType2>
212 class CallResultAndTwoArgumentsSlowPathGenerator
213     : public CallSlowPathGenerator<JumpType, FunctionType, ResultType> {
214 public:
215     CallResultAndTwoArgumentsSlowPathGenerator(
216         JumpType from, SpeculativeJIT* jit, FunctionType function,
217         SpillRegistersMode spillMode, ExceptionCheckRequirement requirement, ResultType result, ArgumentType1 argument1,
218         ArgumentType2 argument2)
219         : CallSlowPathGenerator<JumpType, FunctionType, ResultType>(
220             from, jit, function, spillMode, requirement, result)
221         , m_argument1(argument1)
222         , m_argument2(argument2)
223     {
224     }
225     
226 protected:
227     void generateInternal(SpeculativeJIT* jit) override
228     {
229         this->setUp(jit);
230         this->recordCall(jit->callOperation(this->m_function, extractResult(this->m_result), m_argument1, m_argument2));
231         this->tearDown(jit);
232     }
233
234     ArgumentType1 m_argument1;
235     ArgumentType2 m_argument2;
236 };
237
238 template<
239     typename JumpType, typename FunctionType, typename ResultType,
240     typename ArgumentType1, typename ArgumentType2, typename ArgumentType3>
241 class CallResultAndThreeArgumentsSlowPathGenerator
242     : public CallSlowPathGenerator<JumpType, FunctionType, ResultType> {
243 public:
244     CallResultAndThreeArgumentsSlowPathGenerator(
245         JumpType from, SpeculativeJIT* jit, FunctionType function,
246         SpillRegistersMode spillMode, ExceptionCheckRequirement requirement, ResultType result, ArgumentType1 argument1,
247         ArgumentType2 argument2, ArgumentType3 argument3)
248         : CallSlowPathGenerator<JumpType, FunctionType, ResultType>(
249             from, jit, function, spillMode, requirement, result)
250         , m_argument1(argument1)
251         , m_argument2(argument2)
252         , m_argument3(argument3)
253     {
254     }
255
256 protected:    
257     void generateInternal(SpeculativeJIT* jit) override
258     {
259         this->setUp(jit);
260         this->recordCall(
261             jit->callOperation(
262                 this->m_function, extractResult(this->m_result), m_argument1, m_argument2,
263                 m_argument3));
264         this->tearDown(jit);
265     }
266
267     ArgumentType1 m_argument1;
268     ArgumentType2 m_argument2;
269     ArgumentType3 m_argument3;
270 };
271
272 template<
273     typename JumpType, typename FunctionType, typename ResultType,
274     typename ArgumentType1, typename ArgumentType2, typename ArgumentType3,
275     typename ArgumentType4>
276 class CallResultAndFourArgumentsSlowPathGenerator
277     : public CallSlowPathGenerator<JumpType, FunctionType, ResultType> {
278 public:
279     CallResultAndFourArgumentsSlowPathGenerator(
280         JumpType from, SpeculativeJIT* jit, FunctionType function,
281         SpillRegistersMode spillMode, ExceptionCheckRequirement requirement, ResultType result, ArgumentType1 argument1,
282         ArgumentType2 argument2, ArgumentType3 argument3, ArgumentType4 argument4)
283         : CallSlowPathGenerator<JumpType, FunctionType, ResultType>(
284             from, jit, function, spillMode, requirement, result)
285         , m_argument1(argument1)
286         , m_argument2(argument2)
287         , m_argument3(argument3)
288         , m_argument4(argument4)
289     {
290     }
291     
292 protected:
293     void generateInternal(SpeculativeJIT* jit)
294     {
295         this->setUp(jit);
296         this->recordCall(
297             jit->callOperation(
298                 this->m_function, extractResult(this->m_result), m_argument1, m_argument2,
299                 m_argument3, m_argument4));
300         this->tearDown(jit);
301     }
302
303     ArgumentType1 m_argument1;
304     ArgumentType2 m_argument2;
305     ArgumentType3 m_argument3;
306     ArgumentType4 m_argument4;
307 };
308
309 template<
310     typename JumpType, typename FunctionType, typename ResultType,
311     typename ArgumentType1, typename ArgumentType2, typename ArgumentType3,
312     typename ArgumentType4, typename ArgumentType5>
313 class CallResultAndFiveArgumentsSlowPathGenerator
314     : public CallSlowPathGenerator<JumpType, FunctionType, ResultType> {
315 public:
316     CallResultAndFiveArgumentsSlowPathGenerator(
317         JumpType from, SpeculativeJIT* jit, FunctionType function,
318         SpillRegistersMode spillMode, ExceptionCheckRequirement requirement, ResultType result, ArgumentType1 argument1,
319         ArgumentType2 argument2, ArgumentType3 argument3, ArgumentType4 argument4,
320         ArgumentType5 argument5)
321         : CallSlowPathGenerator<JumpType, FunctionType, ResultType>(
322             from, jit, function, spillMode, requirement, result)
323         , m_argument1(argument1)
324         , m_argument2(argument2)
325         , m_argument3(argument3)
326         , m_argument4(argument4)
327         , m_argument5(argument5)
328     {
329     }
330
331 protected:    
332     void generateInternal(SpeculativeJIT* jit)
333     {
334         this->setUp(jit);
335         this->recordCall(
336             jit->callOperation(
337                 this->m_function, extractResult(this->m_result), m_argument1, m_argument2,
338                 m_argument3, m_argument4, m_argument5));
339         this->tearDown(jit);
340     }
341
342     ArgumentType1 m_argument1;
343     ArgumentType2 m_argument2;
344     ArgumentType3 m_argument3;
345     ArgumentType4 m_argument4;
346     ArgumentType5 m_argument5;
347 };
348
349 template<typename JumpType, typename FunctionType, typename ResultType>
350 inline std::unique_ptr<SlowPathGenerator> slowPathCall(
351     JumpType from, SpeculativeJIT* jit, FunctionType function,
352     ResultType result, SpillRegistersMode spillMode = NeedToSpill, ExceptionCheckRequirement requirement = ExceptionCheckRequirement::CheckNeeded)
353 {
354     return std::make_unique<CallResultAndNoArgumentsSlowPathGenerator<JumpType, FunctionType, ResultType>>(
355         from, jit, function, spillMode, requirement, result);
356 }
357
358 template<
359     typename JumpType, typename FunctionType, typename ResultType,
360     typename ArgumentType1>
361 inline std::unique_ptr<SlowPathGenerator> slowPathCall(
362     JumpType from, SpeculativeJIT* jit, FunctionType function,
363     ResultType result, ArgumentType1 argument1,
364     SpillRegistersMode spillMode = NeedToSpill, ExceptionCheckRequirement requirement = ExceptionCheckRequirement::CheckNeeded)
365 {
366     return std::make_unique<CallResultAndOneArgumentSlowPathGenerator<JumpType, FunctionType, ResultType, ArgumentType1>>(
367         from, jit, function, spillMode, requirement, result, argument1);
368 }
369
370 template<
371     typename JumpType, typename FunctionType, typename ResultType,
372     typename ArgumentType1, typename ArgumentType2>
373 inline std::unique_ptr<SlowPathGenerator> slowPathCall(
374     JumpType from, SpeculativeJIT* jit, FunctionType function,
375     ResultType result, ArgumentType1 argument1, ArgumentType2 argument2,
376     SpillRegistersMode spillMode = NeedToSpill, ExceptionCheckRequirement requirement = ExceptionCheckRequirement::CheckNeeded)
377 {
378     return std::make_unique<CallResultAndTwoArgumentsSlowPathGenerator<JumpType, FunctionType, ResultType, ArgumentType1, ArgumentType2>>(
379         from, jit, function, spillMode, requirement, result, argument1, argument2);
380 }
381
382 template<
383     typename JumpType, typename FunctionType, typename ResultType,
384     typename ArgumentType1, typename ArgumentType2, typename ArgumentType3>
385 inline std::unique_ptr<SlowPathGenerator> slowPathCall(
386     JumpType from, SpeculativeJIT* jit, FunctionType function,
387     ResultType result, ArgumentType1 argument1, ArgumentType2 argument2,
388     ArgumentType3 argument3, SpillRegistersMode spillMode = NeedToSpill, ExceptionCheckRequirement requirement = ExceptionCheckRequirement::CheckNeeded)
389 {
390     return std::make_unique<CallResultAndThreeArgumentsSlowPathGenerator<JumpType, FunctionType, ResultType, ArgumentType1, ArgumentType2,
391         ArgumentType3>>(from, jit, function, spillMode, requirement, result, argument1, argument2, argument3);
392 }
393
394 template<
395     typename JumpType, typename FunctionType, typename ResultType,
396     typename ArgumentType1, typename ArgumentType2, typename ArgumentType3,
397     typename ArgumentType4>
398 inline std::unique_ptr<SlowPathGenerator> slowPathCall(
399     JumpType from, SpeculativeJIT* jit, FunctionType function,
400     ResultType result, ArgumentType1 argument1, ArgumentType2 argument2,
401     ArgumentType3 argument3, ArgumentType4 argument4,
402     SpillRegistersMode spillMode = NeedToSpill, ExceptionCheckRequirement requirement = ExceptionCheckRequirement::CheckNeeded)
403 {
404     return std::make_unique<CallResultAndFourArgumentsSlowPathGenerator<JumpType, FunctionType, ResultType, ArgumentType1, ArgumentType2,
405         ArgumentType3, ArgumentType4>>(from, jit, function, spillMode, requirement, result, argument1, argument2, argument3, argument4);
406 }
407
408 template<
409     typename JumpType, typename FunctionType, typename ResultType,
410     typename ArgumentType1, typename ArgumentType2, typename ArgumentType3,
411     typename ArgumentType4, typename ArgumentType5>
412 inline std::unique_ptr<SlowPathGenerator> slowPathCall(
413     JumpType from, SpeculativeJIT* jit, FunctionType function,
414     ResultType result, ArgumentType1 argument1, ArgumentType2 argument2,
415     ArgumentType3 argument3, ArgumentType4 argument4, ArgumentType5 argument5,
416     SpillRegistersMode spillMode = NeedToSpill, ExceptionCheckRequirement requirement = ExceptionCheckRequirement::CheckNeeded)
417 {
418     return std::make_unique<CallResultAndFiveArgumentsSlowPathGenerator<JumpType, FunctionType, ResultType, ArgumentType1, ArgumentType2,
419         ArgumentType3, ArgumentType4, ArgumentType5>>(from, jit, function, spillMode, requirement, result, argument1, argument2, argument3,
420         argument4, argument5);
421 }
422
423 template<typename JumpType, typename DestinationType, typename SourceType, unsigned numberOfAssignments>
424 class AssigningSlowPathGenerator : public JumpingSlowPathGenerator<JumpType> {
425 public:
426     AssigningSlowPathGenerator(
427         JumpType from, SpeculativeJIT* jit,
428         DestinationType destination[numberOfAssignments],
429         SourceType source[numberOfAssignments])
430         : JumpingSlowPathGenerator<JumpType>(from, jit)
431     {
432         for (unsigned i = numberOfAssignments; i--;) {
433             m_destination[i] = destination[i];
434             m_source[i] = source[i];
435         }
436     }
437
438 protected:
439     void generateInternal(SpeculativeJIT* jit) override
440     {
441         this->linkFrom(jit);
442         for (unsigned i = numberOfAssignments; i--;)
443             jit->m_jit.move(m_source[i], m_destination[i]);
444         this->jumpTo(jit);
445     }
446
447 private:
448     DestinationType m_destination[numberOfAssignments];
449     SourceType m_source[numberOfAssignments];
450 };
451
452 template<typename JumpType, typename DestinationType, typename SourceType, unsigned numberOfAssignments>
453 inline std::unique_ptr<SlowPathGenerator> slowPathMove(
454     JumpType from, SpeculativeJIT* jit, SourceType source[numberOfAssignments], DestinationType destination[numberOfAssignments])
455 {
456     return std::make_unique<AssigningSlowPathGenerator<JumpType, DestinationType, SourceType, numberOfAssignments>>(
457         from, jit, destination, source);
458 }
459
460 template<typename JumpType, typename DestinationType, typename SourceType>
461 inline std::unique_ptr<SlowPathGenerator> slowPathMove(
462     JumpType from, SpeculativeJIT* jit, SourceType source, DestinationType destination)
463 {
464     SourceType sourceArray[1] = { source };
465     DestinationType destinationArray[1] = { destination };
466     return std::make_unique<AssigningSlowPathGenerator<JumpType, DestinationType, SourceType, 1>>(
467         from, jit, destinationArray, sourceArray);
468 }
469
470 template<typename JumpType, typename DestinationType, typename SourceType>
471 inline std::unique_ptr<SlowPathGenerator> slowPathMove(
472     JumpType from, SpeculativeJIT* jit, SourceType source1, DestinationType destination1, SourceType source2, DestinationType destination2)
473 {
474     SourceType sourceArray[2] = { source1, source2 };
475     DestinationType destinationArray[2] = { destination1, destination2 };
476     return std::make_unique<AssigningSlowPathGenerator<JumpType, DestinationType, SourceType, 2>>(
477         from, jit, destinationArray, sourceArray);
478 }
479
480 } } // namespace JSC::DFG
481
482 #endif // ENABLD(DFG_JIT)
483
484 #endif // DFGSlowPathGenerator_h
485