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 | |
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 = 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 | |
67 | protected: |
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 | |
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 : uint8_t { |
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_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 | |
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 | 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 | |
160 | template<typename JumpType, typename FunctionType, typename ResultType, typename... Arguments> |
161 | class CallResultAndArgumentsSlowPathGenerator |
162 | : public CallSlowPathGenerator<JumpType, FunctionType, ResultType> { |
163 | public: |
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 | |
173 | protected: |
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 | |
190 | template<typename JumpType, typename FunctionType, typename ResultType, typename... Arguments> |
191 | inline 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 std::make_unique<CallResultAndArgumentsSlowPathGenerator<JumpType, FunctionType, ResultType, Arguments...>>( |
197 | from, jit, function, spillMode, requirement, result, arguments...); |
198 | } |
199 | |
200 | template<typename JumpType, typename FunctionType, typename ResultType, typename... Arguments> |
201 | inline 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 | |
209 | template<typename JumpType, typename DestinationType, typename SourceType, unsigned numberOfAssignments> |
210 | class AssigningSlowPathGenerator : public JumpingSlowPathGenerator<JumpType> { |
211 | public: |
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 | |
224 | protected: |
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 | |
233 | private: |
234 | DestinationType m_destination[numberOfAssignments]; |
235 | SourceType m_source[numberOfAssignments]; |
236 | }; |
237 | |
238 | template<typename JumpType, typename DestinationType, typename SourceType, unsigned numberOfAssignments> |
239 | inline std::unique_ptr<SlowPathGenerator> slowPathMove( |
240 | JumpType from, SpeculativeJIT* jit, SourceType source[numberOfAssignments], DestinationType destination[numberOfAssignments]) |
241 | { |
242 | return std::make_unique<AssigningSlowPathGenerator<JumpType, DestinationType, SourceType, numberOfAssignments>>( |
243 | from, jit, destination, source); |
244 | } |
245 | |
246 | template<typename JumpType, typename DestinationType, typename SourceType> |
247 | inline 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 std::make_unique<AssigningSlowPathGenerator<JumpType, DestinationType, SourceType, 1>>( |
253 | from, jit, destinationArray, sourceArray); |
254 | } |
255 | |
256 | template<typename JumpType, typename DestinationType, typename SourceType> |
257 | inline 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 std::make_unique<AssigningSlowPathGenerator<JumpType, DestinationType, SourceType, 2>>( |
263 | from, jit, destinationArray, sourceArray); |
264 | } |
265 | |
266 | } } // namespace JSC::DFG |
267 | |
268 | #endif // ENABLD(DFG_JIT) |
269 | |