1/*
2 * Copyright (C) 2012-2018 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 "DFGSilentRegisterSavePlan.h"
31#include "DFGSpeculativeJIT.h"
32#include <wtf/FastMalloc.h>
33#include <wtf/FunctionTraits.h>
34
35namespace JSC { namespace DFG {
36
37class SlowPathGenerator {
38 WTF_MAKE_FAST_ALLOCATED;
39public:
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 = WTF::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
67protected:
68 virtual void generateInternal(SpeculativeJIT*) = 0;
69 Node* m_currentNode;
70 MacroAssembler::Label m_label;
71 unsigned m_streamIndex;
72 NodeOrigin m_origin;
73};
74
75template<typename JumpType>
76class JumpingSlowPathGenerator : public SlowPathGenerator {
77public:
78 JumpingSlowPathGenerator(JumpType from, SpeculativeJIT* jit)
79 : SlowPathGenerator(jit)
80 , m_from(from)
81 , m_to(jit->m_jit.label())
82 {
83 }
84
85protected:
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
100enum class ExceptionCheckRequirement : uint8_t {
101 CheckNeeded,
102 CheckNotNeeded
103};
104
105template<typename JumpType, typename FunctionType, typename ResultType>
106class CallSlowPathGenerator : public JumpingSlowPathGenerator<JumpType> {
107public:
108 CallSlowPathGenerator(
109 JumpType from, SpeculativeJIT* jit, FunctionType function,
110 SpillRegistersMode spillMode, ExceptionCheckRequirement requirement, ResultType result)
111 : JumpingSlowPathGenerator<JumpType>(from, jit)
112 , m_spillMode(spillMode)
113 , m_exceptionCheckRequirement(requirement)
114 , m_result(result)
115 , m_function(function)
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
126protected:
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 for (unsigned i = m_plans.size(); i--;)
145 jit->silentFill(m_plans[i]);
146 }
147 if (m_exceptionCheckRequirement == ExceptionCheckRequirement::CheckNeeded)
148 jit->m_jit.exceptionCheck();
149 this->jumpTo(jit);
150 }
151
152 MacroAssembler::Call m_call;
153 SpillRegistersMode m_spillMode;
154 ExceptionCheckRequirement m_exceptionCheckRequirement;
155 ResultType m_result;
156 FunctionType m_function;
157 Vector<SilentRegisterSavePlan, 2> m_plans;
158};
159
160template<typename JumpType, typename FunctionType, typename ResultType, typename... Arguments>
161class CallResultAndArgumentsSlowPathGenerator
162 : public CallSlowPathGenerator<JumpType, FunctionType, ResultType> {
163public:
164 CallResultAndArgumentsSlowPathGenerator(
165 JumpType from, SpeculativeJIT* jit, FunctionType function,
166 SpillRegistersMode spillMode, ExceptionCheckRequirement requirement, ResultType result, Arguments... arguments)
167 : CallSlowPathGenerator<JumpType, FunctionType, ResultType>(
168 from, jit, function, spillMode, requirement, result)
169 , m_arguments(std::forward<Arguments>(arguments)...)
170 {
171 }
172
173protected:
174 template<size_t... ArgumentsIndex>
175 void unpackAndGenerate(SpeculativeJIT* jit, std::index_sequence<ArgumentsIndex...>)
176 {
177 this->setUp(jit);
178 this->recordCall(jit->callOperation(this->m_function, extractResult(this->m_result), std::get<ArgumentsIndex>(m_arguments)...));
179 this->tearDown(jit);
180 }
181
182 void generateInternal(SpeculativeJIT* jit) override
183 {
184 unpackAndGenerate(jit, std::make_index_sequence<std::tuple_size<std::tuple<Arguments...>>::value>());
185 }
186
187 std::tuple<Arguments...> m_arguments;
188};
189
190template<typename JumpType, typename FunctionType, typename ResultType, typename... Arguments>
191inline std::unique_ptr<SlowPathGenerator> slowPathCall(
192 JumpType from, SpeculativeJIT* jit, FunctionType function,
193 SpillRegistersMode spillMode, ExceptionCheckRequirement requirement,
194 ResultType result, Arguments... arguments)
195{
196 return makeUnique<CallResultAndArgumentsSlowPathGenerator<JumpType, FunctionType, ResultType, Arguments...>>(
197 from, jit, function, spillMode, requirement, result, arguments...);
198}
199
200template<typename JumpType, typename FunctionType, typename ResultType, typename... Arguments>
201inline std::unique_ptr<SlowPathGenerator> slowPathCall(
202 JumpType from, SpeculativeJIT* jit, FunctionType function,
203 ResultType result, Arguments... arguments)
204{
205 return slowPathCall(
206 from, jit, function, NeedToSpill, ExceptionCheckRequirement::CheckNeeded, result, arguments...);
207}
208
209template<typename JumpType, typename DestinationType, typename SourceType, unsigned numberOfAssignments>
210class AssigningSlowPathGenerator : public JumpingSlowPathGenerator<JumpType> {
211public:
212 AssigningSlowPathGenerator(
213 JumpType from, SpeculativeJIT* jit,
214 DestinationType destination[numberOfAssignments],
215 SourceType source[numberOfAssignments])
216 : JumpingSlowPathGenerator<JumpType>(from, jit)
217 {
218 for (unsigned i = numberOfAssignments; i--;) {
219 m_destination[i] = destination[i];
220 m_source[i] = source[i];
221 }
222 }
223
224protected:
225 void generateInternal(SpeculativeJIT* jit) override
226 {
227 this->linkFrom(jit);
228 for (unsigned i = numberOfAssignments; i--;)
229 jit->m_jit.move(m_source[i], m_destination[i]);
230 this->jumpTo(jit);
231 }
232
233private:
234 DestinationType m_destination[numberOfAssignments];
235 SourceType m_source[numberOfAssignments];
236};
237
238template<typename JumpType, typename DestinationType, typename SourceType, unsigned numberOfAssignments>
239inline std::unique_ptr<SlowPathGenerator> slowPathMove(
240 JumpType from, SpeculativeJIT* jit, SourceType source[numberOfAssignments], DestinationType destination[numberOfAssignments])
241{
242 return makeUnique<AssigningSlowPathGenerator<JumpType, DestinationType, SourceType, numberOfAssignments>>(
243 from, jit, destination, source);
244}
245
246template<typename JumpType, typename DestinationType, typename SourceType>
247inline std::unique_ptr<SlowPathGenerator> slowPathMove(
248 JumpType from, SpeculativeJIT* jit, SourceType source, DestinationType destination)
249{
250 SourceType sourceArray[1] = { source };
251 DestinationType destinationArray[1] = { destination };
252 return makeUnique<AssigningSlowPathGenerator<JumpType, DestinationType, SourceType, 1>>(
253 from, jit, destinationArray, sourceArray);
254}
255
256template<typename JumpType, typename DestinationType, typename SourceType>
257inline std::unique_ptr<SlowPathGenerator> slowPathMove(
258 JumpType from, SpeculativeJIT* jit, SourceType source1, DestinationType destination1, SourceType source2, DestinationType destination2)
259{
260 SourceType sourceArray[2] = { source1, source2 };
261 DestinationType destinationArray[2] = { destination1, destination2 };
262 return makeUnique<AssigningSlowPathGenerator<JumpType, DestinationType, SourceType, 2>>(
263 from, jit, destinationArray, sourceArray);
264}
265
266} } // namespace JSC::DFG
267
268#endif // ENABLD(DFG_JIT)
269