1/*
2 * Copyright (C) 2011-2019 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(JIT)
29
30#include "AssemblyHelpers.h"
31#include "FPRInfo.h"
32#include "GPRInfo.h"
33#include "StackAlignment.h"
34#include <wtf/FunctionTraits.h>
35
36namespace JSC {
37
38#if CPU(MIPS) || (OS(WINDOWS) && CPU(X86_64))
39#define POKE_ARGUMENT_OFFSET 4
40#else
41#define POKE_ARGUMENT_OFFSET 0
42#endif
43
44class ExecState;
45class Structure;
46namespace DFG {
47class RegisteredStructure;
48};
49
50class CCallHelpers : public AssemblyHelpers {
51public:
52 CCallHelpers(CodeBlock* codeBlock = 0)
53 : AssemblyHelpers(codeBlock)
54 {
55 }
56
57 // Wrapper to encode JSCell GPR into JSValue.
58 class CellValue {
59 public:
60 explicit CellValue(GPRReg gpr)
61 : m_gpr(gpr)
62 {
63 }
64
65 GPRReg gpr() const { return m_gpr; }
66
67 private:
68 GPRReg m_gpr;
69 };
70
71 // The most general helper for setting arguments that fit in a GPR, if you can compute each
72 // argument without using any argument registers. You usually want one of the setupArguments*()
73 // methods below instead of this. This thing is most useful if you have *a lot* of arguments.
74 template<typename Functor>
75 void setupArgument(unsigned argumentIndex, const Functor& functor)
76 {
77 unsigned numberOfRegs = GPRInfo::numberOfArgumentRegisters; // Disguise the constant from clang's tautological compare warning.
78 if (argumentIndex < numberOfRegs) {
79 functor(GPRInfo::toArgumentRegister(argumentIndex));
80 return;
81 }
82
83 functor(GPRInfo::nonArgGPR0);
84 poke(GPRInfo::nonArgGPR0, POKE_ARGUMENT_OFFSET + argumentIndex - GPRInfo::numberOfArgumentRegisters);
85 }
86
87private:
88
89 template<unsigned NumberOfRegisters, typename RegType>
90 ALWAYS_INLINE void setupStubArgs(std::array<RegType, NumberOfRegisters> destinations, std::array<RegType, NumberOfRegisters> sources)
91 {
92 if (!ASSERT_DISABLED) {
93 RegisterSet set;
94 for (RegType dest : destinations)
95 set.set(dest);
96 ASSERT_WITH_MESSAGE(set.numberOfSetRegisters() == NumberOfRegisters, "Destinations should not be aliased.");
97 }
98
99 typedef std::pair<RegType, RegType> RegPair;
100 Vector<RegPair, NumberOfRegisters> pairs;
101
102 for (unsigned i = 0; i < NumberOfRegisters; ++i) {
103 if (sources[i] != destinations[i])
104 pairs.append(std::make_pair(sources[i], destinations[i]));
105 }
106
107#if !ASSERT_DISABLED
108 auto numUniqueSources = [&] () -> unsigned {
109 RegisterSet set;
110 for (auto& pair : pairs) {
111 RegType source = pair.first;
112 set.set(source);
113 }
114 return set.numberOfSetRegisters();
115 };
116
117 auto numUniqueDests = [&] () -> unsigned {
118 RegisterSet set;
119 for (auto& pair : pairs) {
120 RegType dest = pair.second;
121 set.set(dest);
122 }
123 return set.numberOfSetRegisters();
124 };
125#endif
126
127 while (pairs.size()) {
128 RegisterSet freeDestinations;
129 for (auto& pair : pairs) {
130 RegType dest = pair.second;
131 freeDestinations.set(dest);
132 }
133 for (auto& pair : pairs) {
134 RegType source = pair.first;
135 freeDestinations.clear(source);
136 }
137
138 if (freeDestinations.numberOfSetRegisters()) {
139 bool madeMove = false;
140 for (unsigned i = 0; i < pairs.size(); i++) {
141 auto& pair = pairs[i];
142 RegType source = pair.first;
143 RegType dest = pair.second;
144 if (freeDestinations.get(dest)) {
145 move(source, dest);
146 pairs.remove(i);
147 madeMove = true;
148 break;
149 }
150 }
151 ASSERT_UNUSED(madeMove, madeMove);
152 continue;
153 }
154
155 ASSERT(numUniqueDests() == numUniqueSources());
156 ASSERT(numUniqueDests() == pairs.size());
157 // The set of source and destination registers are equivalent sets. This means we don't have
158 // any free destination registers that won't also clobber a source. We get around this by
159 // exchanging registers.
160
161 RegType source = pairs[0].first;
162 RegType dest = pairs[0].second;
163 swap(source, dest);
164 pairs.remove(0);
165
166 RegType newSource = source;
167 for (auto& pair : pairs) {
168 RegType source = pair.first;
169 if (source == dest) {
170 pair.first = newSource;
171 break;
172 }
173 }
174
175 // We may have introduced pairs that have the same source and destination. Remove those now.
176 for (unsigned i = 0; i < pairs.size(); i++) {
177 auto& pair = pairs[i];
178 if (pair.first == pair.second) {
179 pairs.remove(i);
180 i--;
181 }
182 }
183 }
184 }
185
186#if CPU(MIPS) || (CPU(ARM_THUMB2) && !CPU(ARM_HARDFP))
187 template<unsigned NumCrossSources, unsigned NumberOfRegisters>
188 ALWAYS_INLINE void setupStubCrossArgs(std::array<GPRReg, NumberOfRegisters> destinations, std::array<FPRReg, NumberOfRegisters> sources) {
189 for (unsigned i = 0; i < NumCrossSources; i++) {
190 GPRReg dest = destinations[i];
191 FPRReg source = sources[i];
192
193 moveDouble(source, dest);
194 }
195 }
196#endif
197
198 template<typename RegType>
199 using InfoTypeForReg = decltype(toInfoFromReg(RegType(-1)));
200
201 // extraGPRArgs is used to track 64-bit argument types passed in register on 32-bit architectures.
202 // extraPoke is used to track 64-bit argument types passed on the stack.
203 template<unsigned numGPRArgs, unsigned numGPRSources, unsigned numFPRArgs, unsigned numFPRSources, unsigned numCrossSources, unsigned extraGPRArgs, unsigned extraPoke>
204 struct ArgCollection {
205 ArgCollection()
206 {
207 gprSources.fill(InvalidGPRReg);
208 gprDestinations.fill(InvalidGPRReg);
209 fprSources.fill(InvalidFPRReg);
210 fprDestinations.fill(InvalidFPRReg);
211 crossSources.fill(InvalidFPRReg);
212 crossDestinations.fill(InvalidGPRReg);
213 }
214
215 template<unsigned a, unsigned b, unsigned c, unsigned d, unsigned e, unsigned f, unsigned g>
216 ArgCollection(ArgCollection<a, b, c, d, e, f, g>& other)
217 {
218 gprSources = other.gprSources;
219 gprDestinations = other.gprDestinations;
220 fprSources = other.fprSources;
221 fprDestinations = other.fprDestinations;
222 crossSources = other.crossSources;
223 crossDestinations = other.crossDestinations;
224 }
225
226 ArgCollection<numGPRArgs + 1, numGPRSources + 1, numFPRArgs, numFPRSources, numCrossSources, extraGPRArgs, extraPoke> pushRegArg(GPRReg argument, GPRReg destination)
227 {
228 ArgCollection<numGPRArgs + 1, numGPRSources + 1, numFPRArgs, numFPRSources, numCrossSources, extraGPRArgs, extraPoke> result(*this);
229
230 result.gprSources[numGPRSources] = argument;
231 result.gprDestinations[numGPRSources] = destination;
232 return result;
233 }
234
235 ArgCollection<numGPRArgs, numGPRSources, numFPRArgs + 1, numFPRSources + 1, numCrossSources, extraGPRArgs, extraPoke> pushRegArg(FPRReg argument, FPRReg destination)
236 {
237 ArgCollection<numGPRArgs, numGPRSources, numFPRArgs + 1, numFPRSources + 1, numCrossSources, extraGPRArgs, extraPoke> result(*this);
238
239 result.fprSources[numFPRSources] = argument;
240 result.fprDestinations[numFPRSources] = destination;
241 return result;
242 }
243
244 ArgCollection<numGPRArgs, numGPRSources, numFPRArgs + 1, numFPRSources, numCrossSources + 1, extraGPRArgs, extraPoke> pushRegArg(FPRReg argument, GPRReg destination)
245 {
246 ArgCollection<numGPRArgs, numGPRSources, numFPRArgs + 1, numFPRSources, numCrossSources + 1, extraGPRArgs, extraPoke> result(*this);
247
248 result.crossSources[numCrossSources] = argument;
249 result.crossDestinations[numCrossSources] = destination;
250 return result;
251 }
252
253 ArgCollection<numGPRArgs, numGPRSources + 1, numFPRArgs, numFPRSources, numCrossSources, extraGPRArgs + 1, extraPoke> pushExtraRegArg(GPRReg argument, GPRReg destination)
254 {
255 ArgCollection<numGPRArgs, numGPRSources + 1, numFPRArgs, numFPRSources, numCrossSources, extraGPRArgs + 1, extraPoke> result(*this);
256
257 result.gprSources[numGPRSources] = argument;
258 result.gprDestinations[numGPRSources] = destination;
259 return result;
260 }
261
262 ArgCollection<numGPRArgs + 1, numGPRSources, numFPRArgs, numFPRSources, numCrossSources, extraGPRArgs, extraPoke> addGPRArg()
263 {
264 return ArgCollection<numGPRArgs + 1, numGPRSources, numFPRArgs, numFPRSources, numCrossSources, extraGPRArgs, extraPoke>(*this);
265 }
266
267 ArgCollection<numGPRArgs, numGPRSources, numFPRArgs, numFPRSources, numCrossSources, extraGPRArgs + 1, extraPoke> addGPRExtraArg()
268 {
269 return ArgCollection<numGPRArgs, numGPRSources, numFPRArgs, numFPRSources, numCrossSources, extraGPRArgs + 1, extraPoke>(*this);
270 }
271
272 ArgCollection<numGPRArgs + 1, numGPRSources, numFPRArgs, numFPRSources, numCrossSources, extraGPRArgs, extraPoke> addStackArg(GPRReg)
273 {
274 return ArgCollection<numGPRArgs + 1, numGPRSources, numFPRArgs, numFPRSources, numCrossSources, extraGPRArgs, extraPoke>(*this);
275 }
276
277 ArgCollection<numGPRArgs, numGPRSources, numFPRArgs + 1, numFPRSources, numCrossSources, extraGPRArgs, extraPoke> addStackArg(FPRReg)
278 {
279 return ArgCollection<numGPRArgs, numGPRSources, numFPRArgs + 1, numFPRSources, numCrossSources, extraGPRArgs, extraPoke>(*this);
280 }
281
282 ArgCollection<numGPRArgs, numGPRSources, numFPRArgs, numFPRSources, numCrossSources, extraGPRArgs, extraPoke + 1> addPoke()
283 {
284 return ArgCollection<numGPRArgs, numGPRSources, numFPRArgs, numFPRSources, numCrossSources, extraGPRArgs, extraPoke + 1>(*this);
285 }
286
287#if OS(WINDOWS) && CPU(X86_64)
288 unsigned argCount(GPRReg) { return numGPRArgs + numFPRArgs; }
289 unsigned argCount(FPRReg) { return numGPRArgs + numFPRArgs; }
290#else
291 unsigned argCount(GPRReg) { return numGPRArgs + extraGPRArgs; }
292 unsigned argCount(FPRReg) { return numFPRArgs; }
293#endif
294
295 // store GPR -> GPR assignments
296 std::array<GPRReg, GPRInfo::numberOfRegisters> gprSources;
297 std::array<GPRReg, GPRInfo::numberOfRegisters> gprDestinations;
298
299 // store FPR -> FPR assignments
300 std::array<FPRReg, FPRInfo::numberOfRegisters> fprSources;
301 std::array<FPRReg, FPRInfo::numberOfRegisters> fprDestinations;
302
303 // store FPR -> GPR assignments
304 std::array<FPRReg, GPRInfo::numberOfRegisters> crossSources;
305 std::array<GPRReg, GPRInfo::numberOfRegisters> crossDestinations;
306 };
307
308 template<unsigned TargetSize, typename RegType>
309 std::array<RegType, TargetSize> clampArrayToSize(std::array<RegType, InfoTypeForReg<RegType>::numberOfRegisters> sourceArray)
310 {
311 static_assert(TargetSize <= sourceArray.size(), "TargetSize is bigger than source.size()");
312 RELEASE_ASSERT(TargetSize <= InfoTypeForReg<RegType>::numberOfRegisters);
313
314 std::array<RegType, TargetSize> result { };
315
316 for (unsigned i = 0; i < TargetSize; i++) {
317 ASSERT(sourceArray[i] != static_cast<int32_t>(InfoTypeForReg<RegType>::InvalidIndex));
318 result[i] = sourceArray[i];
319 }
320
321 return result;
322 }
323
324 ALWAYS_INLINE unsigned calculatePokeOffset(unsigned currentGPRArgument, unsigned currentFPRArgument, unsigned numCrossSources, unsigned extraGPRArgs, unsigned extraPoke)
325 {
326 // Clang claims that it cannot find the symbol for FPRReg/GPRReg::numberOfArgumentRegisters when they are passed directly to std::max... seems like a bug
327 unsigned numberOfFPArgumentRegisters = FPRInfo::numberOfArgumentRegisters;
328 unsigned numberOfGPArgumentRegisters = GPRInfo::numberOfArgumentRegisters;
329
330 currentGPRArgument += extraGPRArgs;
331 currentFPRArgument -= numCrossSources;
332 IGNORE_WARNINGS_BEGIN("type-limits")
333 ASSERT(currentGPRArgument >= GPRInfo::numberOfArgumentRegisters || currentFPRArgument >= FPRInfo::numberOfArgumentRegisters);
334 IGNORE_WARNINGS_END
335
336 unsigned pokeOffset = POKE_ARGUMENT_OFFSET + extraPoke;
337 pokeOffset += std::max(currentGPRArgument, numberOfGPArgumentRegisters) - numberOfGPArgumentRegisters;
338 pokeOffset += std::max(currentFPRArgument, numberOfFPArgumentRegisters) - numberOfFPArgumentRegisters;
339 return pokeOffset;
340 }
341
342 template<typename ArgType>
343 ALWAYS_INLINE void pokeForArgument(ArgType arg, unsigned currentGPRArgument, unsigned currentFPRArgument, unsigned numCrossSources, unsigned extraGPRArgs, unsigned extraPoke)
344 {
345 unsigned pokeOffset = calculatePokeOffset(currentGPRArgument, currentFPRArgument, numCrossSources, extraGPRArgs, extraPoke);
346 poke(arg, pokeOffset);
347 }
348
349 ALWAYS_INLINE bool stackAligned(unsigned currentGPRArgument, unsigned currentFPRArgument, unsigned numCrossSources, unsigned extraGPRArgs, unsigned extraPoke)
350 {
351 unsigned pokeOffset = calculatePokeOffset(currentGPRArgument, currentFPRArgument, numCrossSources, extraGPRArgs, extraPoke);
352 return !(pokeOffset & 1);
353 }
354
355 // In the auto-calling convention code below the order of operations is:
356 // 1) spill arguments to stack slots
357 // 2) shuffle incomming argument values in registers to argument registers
358 // 3) fill immediate values to argument registers
359 // To do this, we recurse forwards through our args collecting argument values in registers and spilling stack slots.
360 // when we run out of args we then run our shuffling code to relocate registers. Finally, as we unwind from our
361 // recursion we can fill immediates.
362
363#define CURRENT_ARGUMENT_TYPE typename FunctionTraits<OperationType>::template ArgumentType<numGPRArgs + numFPRArgs>
364#define RESULT_TYPE typename FunctionTraits<OperationType>::ResultType
365
366#if USE(JSVALUE64)
367
368 // Avoid MSVC optimization time explosion associated with __forceinline in recursive templates.
369 template<typename OperationType, unsigned numGPRArgs, unsigned numGPRSources, unsigned numFPRArgs, unsigned numFPRSources, unsigned numCrossSources, unsigned extraGPRArgs, unsigned extraPoke, typename RegType, typename... Args>
370 ALWAYS_INLINE_EXCEPT_MSVC void marshallArgumentRegister(ArgCollection<numGPRArgs, numGPRSources, numFPRArgs, numFPRSources, numCrossSources, extraGPRArgs, extraPoke> argSourceRegs, RegType arg, Args... args)
371 {
372 using InfoType = InfoTypeForReg<RegType>;
373 unsigned numArgRegisters = InfoType::numberOfArgumentRegisters;
374#if OS(WINDOWS) && CPU(X86_64)
375 unsigned currentArgCount = argSourceRegs.argCount(arg) + (std::is_same<RESULT_TYPE, SlowPathReturnType>::value ? 1 : 0);
376#else
377 unsigned currentArgCount = argSourceRegs.argCount(arg);
378#endif
379 if (currentArgCount < numArgRegisters) {
380 auto updatedArgSourceRegs = argSourceRegs.pushRegArg(arg, InfoType::toArgumentRegister(currentArgCount));
381 setupArgumentsImpl<OperationType>(updatedArgSourceRegs, args...);
382 return;
383 }
384
385 pokeForArgument(arg, numGPRArgs, numFPRArgs, numCrossSources, extraGPRArgs, extraPoke);
386 setupArgumentsImpl<OperationType>(argSourceRegs.addStackArg(arg), args...);
387 }
388
389 template<typename OperationType, unsigned numGPRArgs, unsigned numGPRSources, unsigned numFPRArgs, unsigned numFPRSources, unsigned numCrossSources, unsigned extraGPRArgs, unsigned extraPoke, typename... Args>
390 ALWAYS_INLINE void setupArgumentsImpl(ArgCollection<numGPRArgs, numGPRSources, numFPRArgs, numFPRSources, numCrossSources, extraGPRArgs, extraPoke> argSourceRegs, FPRReg arg, Args... args)
391 {
392 static_assert(std::is_same<CURRENT_ARGUMENT_TYPE, double>::value, "We should only be passing FPRRegs to a double");
393 marshallArgumentRegister<OperationType>(argSourceRegs, arg, args...);
394 }
395
396 template<typename OperationType, unsigned numGPRArgs, unsigned numGPRSources, unsigned numFPRArgs, unsigned numFPRSources, unsigned numCrossSources, unsigned extraGPRArgs, unsigned extraPoke, typename... Args>
397 ALWAYS_INLINE void setupArgumentsImpl(ArgCollection<numGPRArgs, numGPRSources, numFPRArgs, numFPRSources, numCrossSources, extraGPRArgs, extraPoke> argSourceRegs, GPRReg arg, Args... args)
398 {
399 marshallArgumentRegister<OperationType>(argSourceRegs, arg, args...);
400 }
401
402 template<typename OperationType, unsigned numGPRArgs, unsigned numGPRSources, unsigned numFPRArgs, unsigned numFPRSources, unsigned numCrossSources, unsigned extraGPRArgs, unsigned extraPoke, typename... Args>
403 ALWAYS_INLINE void setupArgumentsImpl(ArgCollection<numGPRArgs, numGPRSources, numFPRArgs, numFPRSources, numCrossSources, extraGPRArgs, extraPoke> argSourceRegs, JSValueRegs arg, Args... args)
404 {
405 marshallArgumentRegister<OperationType>(argSourceRegs, arg.gpr(), args...);
406 }
407
408 template<typename OperationType, unsigned numGPRArgs, unsigned numGPRSources, unsigned numFPRArgs, unsigned numFPRSources, unsigned numCrossSources, unsigned extraGPRArgs, unsigned extraPoke, typename... Args>
409 ALWAYS_INLINE void setupArgumentsImpl(ArgCollection<numGPRArgs, numGPRSources, numFPRArgs, numFPRSources, numCrossSources, extraGPRArgs, extraPoke> argSourceRegs, CellValue arg, Args... args)
410 {
411 marshallArgumentRegister<OperationType>(argSourceRegs, arg.gpr(), args...);
412 }
413
414#else // USE(JSVALUE64)
415#if CPU(X86)
416
417 template<typename OperationType, unsigned numGPRArgs, unsigned numGPRSources, unsigned numFPRArgs, unsigned numFPRSources, unsigned numCrossSources, unsigned extraGPRArgs, unsigned extraPoke, typename... Args>
418 ALWAYS_INLINE void setupArgumentsImpl(ArgCollection<numGPRArgs, numGPRSources, numFPRArgs, numFPRSources, numCrossSources, extraGPRArgs, extraPoke> argSourceRegs, FPRReg arg, Args... args)
419 {
420 static_assert(std::is_same<CURRENT_ARGUMENT_TYPE, double>::value, "We should only be passing FPRRegs to a double");
421 pokeForArgument(arg, numGPRArgs, numFPRArgs, numCrossSources, extraGPRArgs, extraPoke);
422 setupArgumentsImpl<OperationType>(argSourceRegs.addStackArg(arg).addPoke(), args...);
423 }
424
425 template<typename OperationType, unsigned numGPRArgs, unsigned numGPRSources, unsigned numFPRArgs, unsigned numFPRSources, unsigned numCrossSources, unsigned extraGPRArgs, unsigned extraPoke, typename... Args>
426 ALWAYS_INLINE std::enable_if_t<sizeof(CURRENT_ARGUMENT_TYPE) <= 4>
427 setupArgumentsImpl(ArgCollection<numGPRArgs, numGPRSources, numFPRArgs, numFPRSources, numCrossSources, extraGPRArgs, extraPoke> argSourceRegs, GPRReg arg, Args... args)
428 {
429 pokeForArgument(arg, numGPRArgs, numFPRArgs, numCrossSources, extraGPRArgs, extraPoke);
430 setupArgumentsImpl<OperationType>(argSourceRegs.addGPRArg(), args...);
431 }
432
433 template<typename OperationType, unsigned numGPRArgs, unsigned numGPRSources, unsigned numFPRArgs, unsigned numFPRSources, unsigned numCrossSources, unsigned extraGPRArgs, unsigned extraPoke, typename... Args>
434 ALWAYS_INLINE std::enable_if_t<std::is_same<CURRENT_ARGUMENT_TYPE, EncodedJSValue>::value>
435 setupArgumentsImpl(ArgCollection<numGPRArgs, numGPRSources, numFPRArgs, numFPRSources, numCrossSources, extraGPRArgs, extraPoke> argSourceRegs, CellValue payload, Args... args)
436 {
437 pokeForArgument(payload.gpr(), numGPRArgs, numFPRArgs, numCrossSources, extraGPRArgs, extraPoke);
438 pokeForArgument(TrustedImm32(JSValue::CellTag), numGPRArgs, numFPRArgs, numCrossSources, extraGPRArgs, extraPoke + 1);
439 setupArgumentsImpl<OperationType>(argSourceRegs.addGPRArg().addPoke(), args...);
440 }
441
442 template<typename OperationType, unsigned numGPRArgs, unsigned numGPRSources, unsigned numFPRArgs, unsigned numFPRSources, unsigned numCrossSources, unsigned extraGPRArgs, unsigned extraPoke, typename... Args>
443 ALWAYS_INLINE std::enable_if_t<std::is_same<CURRENT_ARGUMENT_TYPE, EncodedJSValue>::value>
444 setupArgumentsImpl(ArgCollection<numGPRArgs, numGPRSources, numFPRArgs, numFPRSources, numCrossSources, extraGPRArgs, extraPoke> argSourceRegs, JSValueRegs arg, Args... args)
445 {
446 pokeForArgument(arg.payloadGPR(), numGPRArgs, numFPRArgs, numCrossSources, extraGPRArgs, extraPoke);
447 pokeForArgument(arg.tagGPR(), numGPRArgs, numFPRArgs, numCrossSources, extraGPRArgs, extraPoke + 1);
448 setupArgumentsImpl<OperationType>(argSourceRegs.addGPRArg().addPoke(), args...);
449 }
450
451#elif CPU(ARM_THUMB2) || CPU(MIPS)
452
453 template<typename OperationType, unsigned numGPRArgs, unsigned numGPRSources, unsigned numFPRArgs, unsigned numFPRSources, unsigned numCrossSources, unsigned extraGPRArgs, unsigned extraPoke, typename... Args>
454 void setupArgumentsImpl(ArgCollection<numGPRArgs, numGPRSources, numFPRArgs, numFPRSources, numCrossSources, extraGPRArgs, extraPoke> argSourceRegs, FPRReg arg, Args... args)
455 {
456 static_assert(std::is_same<CURRENT_ARGUMENT_TYPE, double>::value, "We should only be passing FPRRegs to a double");
457
458 // MIPS and ARM-hardfp pass FP arguments in FP registers.
459#if CPU(MIPS)
460 unsigned numberOfFPArgumentRegisters = FPRInfo::numberOfArgumentRegisters;
461 unsigned currentFPArgCount = argSourceRegs.argCount(arg);
462
463 // MIPS can only use FP argument registers if it isn't preceeded by any GP argument.
464 if (currentFPArgCount < numberOfFPArgumentRegisters && !numGPRArgs) {
465 auto updatedArgSourceRegs = argSourceRegs.pushRegArg(arg, FPRInfo::toArgumentRegister(currentFPArgCount));
466 setupArgumentsImpl<OperationType>(updatedArgSourceRegs.addGPRExtraArg().addGPRExtraArg(), args...);
467 return;
468 }
469#elif CPU(ARM_THUMB2) && CPU(ARM_HARDFP)
470 unsigned numberOfFPArgumentRegisters = FPRInfo::numberOfArgumentRegisters;
471 unsigned currentFPArgCount = argSourceRegs.argCount(arg);
472
473 if (currentFPArgCount < numberOfFPArgumentRegisters) {
474 auto updatedArgSourceRegs = argSourceRegs.pushRegArg(arg, FPRInfo::toArgumentRegister(currentFPArgCount));
475 setupArgumentsImpl<OperationType>(updatedArgSourceRegs, args...);
476 return;
477 }
478#endif
479
480#if CPU(MIPS) || (CPU(ARM_THUMB2) && !CPU(ARM_HARDFP))
481 // On MIPS and ARM-softfp FP arguments can be passed in GP registers.
482 unsigned numberOfGPArgumentRegisters = GPRInfo::numberOfArgumentRegisters;
483 unsigned currentGPArgCount = argSourceRegs.argCount(GPRInfo::regT0);
484 unsigned alignedGPArgCount = roundUpToMultipleOf<2>(currentGPArgCount);
485
486 if (alignedGPArgCount + 1 < numberOfGPArgumentRegisters) {
487 auto updatedArgSourceRegs = argSourceRegs.pushRegArg(arg, GPRInfo::toArgumentRegister(alignedGPArgCount));
488
489 if (alignedGPArgCount > currentGPArgCount)
490 setupArgumentsImpl<OperationType>(updatedArgSourceRegs.addGPRExtraArg().addGPRExtraArg().addGPRExtraArg(), args...);
491 else
492 setupArgumentsImpl<OperationType>(updatedArgSourceRegs.addGPRExtraArg().addGPRExtraArg(), args...);
493
494 return;
495 }
496
497 if (currentGPArgCount < numberOfGPArgumentRegisters) {
498 pokeForArgument(arg, numGPRArgs, numFPRArgs, numCrossSources, extraGPRArgs + 1, extraPoke);
499 setupArgumentsImpl<OperationType>(argSourceRegs.addGPRExtraArg().addStackArg(arg).addPoke(), args...);
500 return;
501 }
502#endif
503
504 // Otherwise pass FP argument on stack.
505 if (stackAligned(numGPRArgs, numFPRArgs, numCrossSources, extraGPRArgs, extraPoke)) {
506 pokeForArgument(arg, numGPRArgs, numFPRArgs, numCrossSources, extraGPRArgs, extraPoke);
507 setupArgumentsImpl<OperationType>(argSourceRegs.addStackArg(arg).addPoke(), args...);
508 } else {
509 pokeForArgument(arg, numGPRArgs, numFPRArgs, numCrossSources, extraGPRArgs, extraPoke + 1);
510 setupArgumentsImpl<OperationType>(argSourceRegs.addStackArg(arg).addPoke().addPoke(), args...);
511 }
512 }
513
514 template<typename OperationType, unsigned numGPRArgs, unsigned numGPRSources, unsigned numFPRArgs, unsigned numFPRSources, unsigned numCrossSources, unsigned extraGPRArgs, unsigned extraPoke, typename... Args>
515 std::enable_if_t<sizeof(CURRENT_ARGUMENT_TYPE) <= 4>
516 setupArgumentsImpl(ArgCollection<numGPRArgs, numGPRSources, numFPRArgs, numFPRSources, numCrossSources, extraGPRArgs, extraPoke> argSourceRegs, GPRReg arg, Args... args)
517 {
518 unsigned numArgRegisters = GPRInfo::numberOfArgumentRegisters;
519 unsigned currentArgCount = argSourceRegs.argCount(arg);
520 if (currentArgCount < numArgRegisters) {
521 auto updatedArgSourceRegs = argSourceRegs.pushRegArg(arg, GPRInfo::toArgumentRegister(currentArgCount));
522 setupArgumentsImpl<OperationType>(updatedArgSourceRegs, args...);
523 return;
524 }
525
526 pokeForArgument(arg, numGPRArgs, numFPRArgs, numCrossSources, extraGPRArgs, extraPoke);
527 setupArgumentsImpl<OperationType>(argSourceRegs.addStackArg(arg), args...);
528 }
529
530 template<typename OperationType, typename Arg1, typename Arg2, unsigned numGPRArgs, unsigned numGPRSources, unsigned numFPRArgs, unsigned numFPRSources, unsigned numCrossSources, unsigned extraGPRArgs, unsigned extraPoke, typename... Args>
531 void pokeArgumentsAligned(ArgCollection<numGPRArgs, numGPRSources, numFPRArgs, numFPRSources, numCrossSources, extraGPRArgs, extraPoke> argSourceRegs, Arg1 arg1, Arg2 arg2, Args... args)
532 {
533 unsigned numArgRegisters = GPRInfo::numberOfArgumentRegisters;
534 unsigned currentArgCount = argSourceRegs.argCount(GPRInfo::regT0);
535
536 if (currentArgCount + 1 == numArgRegisters) {
537 pokeForArgument(arg1, numGPRArgs, numFPRArgs, numCrossSources, extraGPRArgs + 1, extraPoke);
538 pokeForArgument(arg2, numGPRArgs, numFPRArgs, numCrossSources, extraGPRArgs + 1, extraPoke + 1);
539 setupArgumentsImpl<OperationType>(argSourceRegs.addGPRExtraArg().addGPRArg().addPoke(), args...);
540 } else if (stackAligned(numGPRArgs, numFPRArgs, numCrossSources, extraGPRArgs, extraPoke)) {
541 pokeForArgument(arg1, numGPRArgs, numFPRArgs, numCrossSources, extraGPRArgs, extraPoke);
542 pokeForArgument(arg2, numGPRArgs, numFPRArgs, numCrossSources, extraGPRArgs, extraPoke + 1);
543 setupArgumentsImpl<OperationType>(argSourceRegs.addGPRArg().addPoke(), args...);
544 } else {
545 pokeForArgument(arg1, numGPRArgs, numFPRArgs, numCrossSources, extraGPRArgs, extraPoke + 1);
546 pokeForArgument(arg2, numGPRArgs, numFPRArgs, numCrossSources, extraGPRArgs, extraPoke + 2);
547 setupArgumentsImpl<OperationType>(argSourceRegs.addGPRArg().addPoke().addPoke(), args...);
548 }
549 }
550
551 template<typename OperationType, unsigned numGPRArgs, unsigned numGPRSources, unsigned numFPRArgs, unsigned numFPRSources, unsigned numCrossSources, unsigned extraGPRArgs, unsigned extraPoke, typename... Args>
552 std::enable_if_t<std::is_same<CURRENT_ARGUMENT_TYPE, EncodedJSValue>::value>
553 setupArgumentsImpl(ArgCollection<numGPRArgs, numGPRSources, numFPRArgs, numFPRSources, numCrossSources, extraGPRArgs, extraPoke> argSourceRegs, CellValue payload, Args... args)
554 {
555 unsigned numArgRegisters = GPRInfo::numberOfArgumentRegisters;
556 unsigned currentArgCount = argSourceRegs.argCount(payload.gpr());
557 unsigned alignedArgCount = roundUpToMultipleOf<2>(currentArgCount);
558
559 if (alignedArgCount + 1 < numArgRegisters) {
560 auto updatedArgSourceRegs = argSourceRegs.pushRegArg(payload.gpr(), GPRInfo::toArgumentRegister(alignedArgCount));
561
562 if (alignedArgCount > currentArgCount)
563 setupArgumentsImpl<OperationType>(updatedArgSourceRegs.addGPRExtraArg().addGPRExtraArg(), args...);
564 else
565 setupArgumentsImpl<OperationType>(updatedArgSourceRegs.addGPRExtraArg(), args...);
566
567 move(TrustedImm32(JSValue::CellTag), GPRInfo::toArgumentRegister(alignedArgCount + 1));
568
569 } else
570 pokeArgumentsAligned<OperationType>(argSourceRegs, payload.gpr(), TrustedImm32(JSValue::CellTag), args...);
571 }
572
573 template<typename OperationType, unsigned numGPRArgs, unsigned numGPRSources, unsigned numFPRArgs, unsigned numFPRSources, unsigned numCrossSources, unsigned extraGPRArgs, unsigned extraPoke, typename... Args>
574 std::enable_if_t<std::is_same<CURRENT_ARGUMENT_TYPE, EncodedJSValue>::value>
575 setupArgumentsImpl(ArgCollection<numGPRArgs, numGPRSources, numFPRArgs, numFPRSources, numCrossSources, extraGPRArgs, extraPoke> argSourceRegs, JSValueRegs arg, Args... args)
576 {
577 unsigned numArgRegisters = GPRInfo::numberOfArgumentRegisters;
578 unsigned currentArgCount = argSourceRegs.argCount(arg.tagGPR());
579 unsigned alignedArgCount = roundUpToMultipleOf<2>(currentArgCount);
580
581 if (alignedArgCount + 1 < numArgRegisters) {
582 // JSValueRegs is passed in two 32-bit registers on these architectures. Increase both numGPRArgs and extraGPRArgs by 1.
583 // We can't just add 2 to numGPRArgs, since it is used for CURRENT_ARGUMENT_TYPE. Adding 2 would lead to a skipped argument.
584 auto updatedArgSourceRegs1 = argSourceRegs.pushRegArg(arg.payloadGPR(), GPRInfo::toArgumentRegister(alignedArgCount));
585 auto updatedArgSourceRegs2 = updatedArgSourceRegs1.pushExtraRegArg(arg.tagGPR(), GPRInfo::toArgumentRegister(alignedArgCount + 1));
586
587 if (alignedArgCount > currentArgCount)
588 setupArgumentsImpl<OperationType>(updatedArgSourceRegs2.addGPRExtraArg(), args...);
589 else
590 setupArgumentsImpl<OperationType>(updatedArgSourceRegs2, args...);
591 } else
592 pokeArgumentsAligned<OperationType>(argSourceRegs, arg.payloadGPR(), arg.tagGPR(), args...);
593 }
594
595#endif // CPU(ARM_THUMB2) || CPU(MIPS)
596#endif // USE(JSVALUE64)
597
598 template<typename OperationType, unsigned numGPRArgs, unsigned numGPRSources, unsigned numFPRArgs, unsigned numFPRSources, unsigned numCrossSources, unsigned extraGPRArgs, unsigned extraPoke, typename Arg, typename... Args>
599 ALWAYS_INLINE std::enable_if_t<
600 std::is_base_of<TrustedImm, Arg>::value
601 || std::is_convertible<Arg, TrustedImm>::value> // We have this since DFGSpeculativeJIT has it's own implementation of TrustedImmPtr
602 setupArgumentsImpl(ArgCollection<numGPRArgs, numGPRSources, numFPRArgs, numFPRSources, numCrossSources, extraGPRArgs, extraPoke> argSourceRegs, Arg arg, Args... args)
603 {
604 // Right now this only supports non-floating point immediate arguments since we never call operations with non-register values.
605 // If we ever needed to support immediate floating point arguments we would need to duplicate this logic for both types, which sounds
606 // gross so it's probably better to do that marshalling before the call operation...
607 static_assert(!std::is_floating_point<CURRENT_ARGUMENT_TYPE>::value, "We don't support immediate floats/doubles in setupArguments");
608 auto numArgRegisters = GPRInfo::numberOfArgumentRegisters;
609#if OS(WINDOWS) && CPU(X86_64)
610 auto currentArgCount = numGPRArgs + numFPRArgs + (std::is_same<RESULT_TYPE, SlowPathReturnType>::value ? 1 : 0);
611#else
612 auto currentArgCount = numGPRArgs + extraGPRArgs;
613#endif
614 if (currentArgCount < numArgRegisters) {
615 setupArgumentsImpl<OperationType>(argSourceRegs.addGPRArg(), args...);
616 move(arg, GPRInfo::toArgumentRegister(currentArgCount));
617 return;
618 }
619
620 pokeForArgument(arg, numGPRArgs, numFPRArgs, numCrossSources, extraGPRArgs, extraPoke);
621 setupArgumentsImpl<OperationType>(argSourceRegs.addGPRArg(), args...);
622 }
623
624 template<typename OperationType, unsigned numGPRArgs, unsigned numGPRSources, unsigned numFPRArgs, unsigned numFPRSources, unsigned numCrossSources, unsigned extraGPRArgs, unsigned extraPoke, typename Arg, typename... Args>
625 ALWAYS_INLINE std::enable_if_t<
626 std::is_same<CURRENT_ARGUMENT_TYPE, Arg>::value
627 && std::is_integral<CURRENT_ARGUMENT_TYPE>::value
628 && (sizeof(CURRENT_ARGUMENT_TYPE) <= 4)>
629 setupArgumentsImpl(ArgCollection<numGPRArgs, numGPRSources, numFPRArgs, numFPRSources, numCrossSources, extraGPRArgs, extraPoke> argSourceRegs, Arg arg, Args... args)
630 {
631 setupArgumentsImpl<OperationType>(argSourceRegs, TrustedImm32(arg), args...);
632 }
633
634 template<typename OperationType, unsigned numGPRArgs, unsigned numGPRSources, unsigned numFPRArgs, unsigned numFPRSources, unsigned numCrossSources, unsigned extraGPRArgs, unsigned extraPoke, typename Arg, typename... Args>
635 ALWAYS_INLINE std::enable_if_t<
636 std::is_same<CURRENT_ARGUMENT_TYPE, Arg>::value
637 && std::is_integral<CURRENT_ARGUMENT_TYPE>::value
638 && (sizeof(CURRENT_ARGUMENT_TYPE) == 8)>
639 setupArgumentsImpl(ArgCollection<numGPRArgs, numGPRSources, numFPRArgs, numFPRSources, numCrossSources, extraGPRArgs, extraPoke> argSourceRegs, Arg arg, Args... args)
640 {
641 setupArgumentsImpl<OperationType>(argSourceRegs, TrustedImm64(arg), args...);
642 }
643
644 template<typename OperationType, unsigned numGPRArgs, unsigned numGPRSources, unsigned numFPRArgs, unsigned numFPRSources, unsigned numCrossSources, unsigned extraGPRArgs, unsigned extraPoke, typename Arg, typename... Args>
645 ALWAYS_INLINE std::enable_if_t<
646 std::is_pointer<CURRENT_ARGUMENT_TYPE>::value
647 && ((std::is_pointer<Arg>::value && std::is_convertible<std::remove_const_t<std::remove_pointer_t<Arg>>*, CURRENT_ARGUMENT_TYPE>::value)
648 || std::is_same<Arg, std::nullptr_t>::value)>
649 setupArgumentsImpl(ArgCollection<numGPRArgs, numGPRSources, numFPRArgs, numFPRSources, numCrossSources, extraGPRArgs, extraPoke> argSourceRegs, Arg arg, Args... args)
650 {
651 setupArgumentsImpl<OperationType>(argSourceRegs, TrustedImmPtr(arg), args...);
652 }
653
654 // Special case DFG::RegisteredStructure because it's really annoying to deal with otherwise...
655 template<typename OperationType, unsigned numGPRArgs, unsigned numGPRSources, unsigned numFPRArgs, unsigned numFPRSources, unsigned numCrossSources, unsigned extraGPRArgs, unsigned extraPoke, typename Arg, typename... Args>
656 ALWAYS_INLINE std::enable_if_t<
657 std::is_same<CURRENT_ARGUMENT_TYPE, Structure*>::value
658 && std::is_same<Arg, DFG::RegisteredStructure>::value>
659 setupArgumentsImpl(ArgCollection<numGPRArgs, numGPRSources, numFPRArgs, numFPRSources, numCrossSources, extraGPRArgs, extraPoke> argSourceRegs, Arg arg, Args... args)
660 {
661 setupArgumentsImpl<OperationType>(argSourceRegs, TrustedImmPtr(arg.get()), args...);
662 }
663
664#undef CURRENT_ARGUMENT_TYPE
665#undef RESULT_TYPE
666
667 // Base case; set up the argument registers.
668 template<typename OperationType, unsigned numGPRArgs, unsigned numGPRSources, unsigned numFPRArgs, unsigned numFPRSources, unsigned numCrossSources, unsigned extraGPRArgs, unsigned extraPoke>
669 ALWAYS_INLINE void setupArgumentsImpl(ArgCollection<numGPRArgs, numGPRSources, numFPRArgs, numFPRSources, numCrossSources, extraGPRArgs, extraPoke> argSourceRegs)
670 {
671 static_assert(FunctionTraits<OperationType>::arity == numGPRArgs + numFPRArgs, "One last sanity check");
672#if USE(JSVALUE64) || CPU(X86)
673 static_assert(FunctionTraits<OperationType>::cCallArity() == numGPRArgs + numFPRArgs + extraPoke, "Check the CCall arity");
674#endif
675 setupStubArgs<numGPRSources, GPRReg>(clampArrayToSize<numGPRSources, GPRReg>(argSourceRegs.gprDestinations), clampArrayToSize<numGPRSources, GPRReg>(argSourceRegs.gprSources));
676#if CPU(MIPS) || (CPU(ARM_THUMB2) && !CPU(ARM_HARDFP))
677 setupStubCrossArgs<numCrossSources>(argSourceRegs.crossDestinations, argSourceRegs.crossSources);
678#else
679 static_assert(!numCrossSources, "shouldn't be used on this architecture.");
680#endif
681 setupStubArgs<numFPRSources, FPRReg>(clampArrayToSize<numFPRSources, FPRReg>(argSourceRegs.fprDestinations), clampArrayToSize<numFPRSources, FPRReg>(argSourceRegs.fprSources));
682 }
683
684public:
685
686#define FIRST_ARGUMENT_TYPE typename FunctionTraits<OperationType>::template ArgumentType<0>
687
688 template<typename OperationType, typename... Args>
689 ALWAYS_INLINE std::enable_if_t<std::is_same<FIRST_ARGUMENT_TYPE, ExecState*>::value> setupArguments(Args... args)
690 {
691#if USE(JSVALUE64)
692 // This only really works for 64-bit since jsvalue regs mess things up for 32-bit...
693 static_assert(FunctionTraits<OperationType>::cCallArity() == sizeof...(Args) + 1, "Basic sanity check");
694#endif
695 setupArgumentsImpl<OperationType, 0, 0, 0, 0, 0, 0, 0>(ArgCollection<0, 0, 0, 0, 0, 0, 0>(), GPRInfo::callFrameRegister, args...);
696 }
697
698 template<typename OperationType, typename... Args>
699 ALWAYS_INLINE std::enable_if_t<!std::is_same<FIRST_ARGUMENT_TYPE, ExecState*>::value> setupArguments(Args... args)
700 {
701#if USE(JSVALUE64)
702 // This only really works for 64-bit since jsvalue regs mess things up for 32-bit...
703 static_assert(FunctionTraits<OperationType>::cCallArity() == sizeof...(Args), "Basic sanity check");
704#endif
705 setupArgumentsImpl<OperationType, 0, 0, 0, 0, 0, 0, 0>(ArgCollection<0, 0, 0, 0, 0, 0, 0>(), args...);
706 }
707
708#undef FIRST_ARGUMENT_TYPE
709
710 void setupResults(GPRReg destA, GPRReg destB)
711 {
712 GPRReg srcA = GPRInfo::returnValueGPR;
713 GPRReg srcB = GPRInfo::returnValueGPR2;
714
715 if (destA == InvalidGPRReg)
716 move(srcB, destB);
717 else if (destB == InvalidGPRReg)
718 move(srcA, destA);
719 else if (srcB != destA) {
720 // Handle the easy cases - two simple moves.
721 move(srcA, destA);
722 move(srcB, destB);
723 } else if (srcA != destB) {
724 // Handle the non-swap case - just put srcB in place first.
725 move(srcB, destB);
726 move(srcA, destA);
727 } else
728 swap(destA, destB);
729 }
730
731 void setupResults(JSValueRegs regs)
732 {
733#if USE(JSVALUE64)
734 move(GPRInfo::returnValueGPR, regs.gpr());
735#else
736 setupResults(regs.payloadGPR(), regs.tagGPR());
737#endif
738 }
739
740 void jumpToExceptionHandler(VM& vm)
741 {
742 // genericUnwind() leaves the handler CallFrame* in vm->callFrameForCatch,
743 // and the address of the handler in vm->targetMachinePCForThrow.
744 loadPtr(&vm.targetMachinePCForThrow, GPRInfo::regT1);
745 jump(GPRInfo::regT1, ExceptionHandlerPtrTag);
746 }
747
748 void prepareForTailCallSlow(GPRReg calleeGPR = InvalidGPRReg)
749 {
750 GPRReg temp1 = calleeGPR == GPRInfo::regT0 ? GPRInfo::regT3 : GPRInfo::regT0;
751 GPRReg temp2 = calleeGPR == GPRInfo::regT1 ? GPRInfo::regT3 : GPRInfo::regT1;
752 GPRReg temp3 = calleeGPR == GPRInfo::regT2 ? GPRInfo::regT3 : GPRInfo::regT2;
753
754 GPRReg newFramePointer = temp1;
755 GPRReg newFrameSizeGPR = temp2;
756 {
757 // The old frame size is its number of arguments (or number of
758 // parameters in case of arity fixup), plus the frame header size,
759 // aligned
760 GPRReg oldFrameSizeGPR = temp2;
761 {
762 GPRReg argCountGPR = oldFrameSizeGPR;
763 load32(Address(framePointerRegister, CallFrameSlot::argumentCount * static_cast<int>(sizeof(Register)) + PayloadOffset), argCountGPR);
764
765 {
766 GPRReg numParametersGPR = temp1;
767 {
768 GPRReg codeBlockGPR = numParametersGPR;
769 loadPtr(Address(framePointerRegister, CallFrameSlot::codeBlock * static_cast<int>(sizeof(Register))), codeBlockGPR);
770 load32(Address(codeBlockGPR, CodeBlock::offsetOfNumParameters()), numParametersGPR);
771 }
772
773 ASSERT(numParametersGPR != argCountGPR);
774 Jump argumentCountWasNotFixedUp = branch32(BelowOrEqual, numParametersGPR, argCountGPR);
775 move(numParametersGPR, argCountGPR);
776 argumentCountWasNotFixedUp.link(this);
777 }
778
779 add32(TrustedImm32(stackAlignmentRegisters() + CallFrame::headerSizeInRegisters - 1), argCountGPR, oldFrameSizeGPR);
780 and32(TrustedImm32(-stackAlignmentRegisters()), oldFrameSizeGPR);
781 // We assume < 2^28 arguments
782 mul32(TrustedImm32(sizeof(Register)), oldFrameSizeGPR, oldFrameSizeGPR);
783 }
784
785 // The new frame pointer is at framePointer + oldFrameSize - newFrameSize
786 ASSERT(newFramePointer != oldFrameSizeGPR);
787 addPtr(framePointerRegister, oldFrameSizeGPR, newFramePointer);
788
789 // The new frame size is just the number of arguments plus the
790 // frame header size, aligned
791 ASSERT(newFrameSizeGPR != newFramePointer);
792 load32(Address(stackPointerRegister, CallFrameSlot::argumentCount * static_cast<int>(sizeof(Register)) + PayloadOffset - sizeof(CallerFrameAndPC)),
793 newFrameSizeGPR);
794 add32(TrustedImm32(stackAlignmentRegisters() + CallFrame::headerSizeInRegisters - 1), newFrameSizeGPR);
795 and32(TrustedImm32(-stackAlignmentRegisters()), newFrameSizeGPR);
796 // We assume < 2^28 arguments
797 mul32(TrustedImm32(sizeof(Register)), newFrameSizeGPR, newFrameSizeGPR);
798 }
799
800 GPRReg tempGPR = temp3;
801 ASSERT(tempGPR != newFramePointer && tempGPR != newFrameSizeGPR);
802
803 // We don't need the current frame beyond this point. Masquerade as our
804 // caller.
805#if CPU(ARM_THUMB2) || CPU(ARM64)
806 loadPtr(Address(framePointerRegister, CallFrame::returnPCOffset()), linkRegister);
807 subPtr(TrustedImm32(2 * sizeof(void*)), newFrameSizeGPR);
808#if CPU(ARM64E)
809 addPtr(TrustedImm32(sizeof(CallerFrameAndPC)), MacroAssembler::framePointerRegister, tempGPR);
810 untagPtr(tempGPR, linkRegister);
811#endif
812#elif CPU(MIPS)
813 loadPtr(Address(framePointerRegister, sizeof(void*)), returnAddressRegister);
814 subPtr(TrustedImm32(2 * sizeof(void*)), newFrameSizeGPR);
815#elif CPU(X86) || CPU(X86_64)
816 loadPtr(Address(framePointerRegister, sizeof(void*)), tempGPR);
817 push(tempGPR);
818 subPtr(TrustedImm32(sizeof(void*)), newFrameSizeGPR);
819#else
820 UNREACHABLE_FOR_PLATFORM();
821#endif
822 subPtr(newFrameSizeGPR, newFramePointer);
823 loadPtr(Address(framePointerRegister), framePointerRegister);
824
825
826 // We need to move the newFrameSizeGPR slots above the stack pointer by
827 // newFramePointer registers. We use pointer-sized chunks.
828 MacroAssembler::Label copyLoop(label());
829
830 subPtr(TrustedImm32(sizeof(void*)), newFrameSizeGPR);
831 loadPtr(BaseIndex(stackPointerRegister, newFrameSizeGPR, TimesOne), tempGPR);
832 storePtr(tempGPR, BaseIndex(newFramePointer, newFrameSizeGPR, TimesOne));
833
834 branchTest32(MacroAssembler::NonZero, newFrameSizeGPR).linkTo(copyLoop, this);
835
836 // Ready for a jump!
837 move(newFramePointer, stackPointerRegister);
838 }
839
840 // These operations clobber all volatile registers. They assume that there is room on the top of
841 // stack to marshall call arguments.
842 void logShadowChickenProloguePacket(GPRReg shadowPacket, GPRReg scratch1, GPRReg scope);
843 void logShadowChickenTailPacket(GPRReg shadowPacket, JSValueRegs thisRegs, GPRReg scope, CodeBlock*, CallSiteIndex);
844 // Leaves behind a pointer to the Packet we should write to in shadowPacket.
845 void ensureShadowChickenPacket(VM&, GPRReg shadowPacket, GPRReg scratch1NonArgGPR, GPRReg scratch2);
846};
847
848} // namespace JSC
849
850#endif // ENABLE(JIT)
851