352214b5c1cc32956bcc7e71fd0f4c14848c467f
[WebKit-https.git] / Source / JavaScriptCore / jit / CCallHelpers.h
1 /*
2  * Copyright (C) 2011, 2015-2016 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
36 namespace 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
44 // EncodedJSValue in JSVALUE32_64 is a 64-bit integer. When being compiled in ARM EABI, it must be aligned even-numbered register (r0, r2 or [sp]).
45 // To avoid assemblies from using wrong registers, let's occupy r1 or r3 with a dummy argument when necessary.
46 #if (COMPILER_SUPPORTS(EABI) && CPU(ARM)) || CPU(MIPS)
47 #define EABI_32BIT_DUMMY_ARG      CCallHelpers::TrustedImm32(0),
48 #else
49 #define EABI_32BIT_DUMMY_ARG
50 #endif
51
52 class ExecState;
53 class Structure;
54 namespace DFG {
55 class RegisteredStructure;
56 };
57
58 class CCallHelpers : public AssemblyHelpers {
59 public:
60     CCallHelpers(CodeBlock* codeBlock = 0)
61         : AssemblyHelpers(codeBlock)
62     {
63     }
64
65     // The most general helper for setting arguments that fit in a GPR, if you can compute each
66     // argument without using any argument registers. You usually want one of the setupArguments*()
67     // methods below instead of this. This thing is most useful if you have *a lot* of arguments.
68     template<typename Functor>
69     void setupArgument(unsigned argumentIndex, const Functor& functor)
70     {
71         unsigned numberOfRegs = GPRInfo::numberOfArgumentRegisters; // Disguise the constant from clang's tautological compare warning.
72         if (argumentIndex < numberOfRegs) {
73             functor(GPRInfo::toArgumentRegister(argumentIndex));
74             return;
75         }
76
77         functor(GPRInfo::nonArgGPR0);
78         poke(GPRInfo::nonArgGPR0, POKE_ARGUMENT_OFFSET + argumentIndex - GPRInfo::numberOfArgumentRegisters);
79     }
80
81 private:
82
83     template<unsigned NumberOfRegisters, typename RegType>
84     ALWAYS_INLINE void setupStubArgs(std::array<RegType, NumberOfRegisters> destinations, std::array<RegType, NumberOfRegisters> sources)
85     {
86         if (!ASSERT_DISABLED) {
87             RegisterSet set;
88             for (RegType dest : destinations)
89                 set.set(dest);
90             ASSERT_WITH_MESSAGE(set.numberOfSetRegisters() == NumberOfRegisters, "Destinations should not be aliased.");
91         }
92
93         typedef std::pair<RegType, RegType> RegPair;
94         Vector<RegPair, NumberOfRegisters> pairs;
95
96         for (unsigned i = 0; i < NumberOfRegisters; ++i) {
97             if (sources[i] != destinations[i])
98                 pairs.append(std::make_pair(sources[i], destinations[i]));
99         }
100
101 #if !ASSERT_DISABLED
102         auto numUniqueSources = [&] () -> unsigned {
103             RegisterSet set;
104             for (auto& pair : pairs) {
105                 RegType source = pair.first;
106                 set.set(source);
107             }
108             return set.numberOfSetRegisters();
109         };
110
111         auto numUniqueDests = [&] () -> unsigned {
112             RegisterSet set;
113             for (auto& pair : pairs) {
114                 RegType dest = pair.second;
115                 set.set(dest);
116             }
117             return set.numberOfSetRegisters();
118         };
119 #endif
120
121         while (pairs.size()) {
122             RegisterSet freeDestinations;
123             for (auto& pair : pairs) {
124                 RegType dest = pair.second;
125                 freeDestinations.set(dest);
126             }
127             for (auto& pair : pairs) {
128                 RegType source = pair.first;
129                 freeDestinations.clear(source);
130             }
131
132             if (freeDestinations.numberOfSetRegisters()) {
133                 bool madeMove = false;
134                 for (unsigned i = 0; i < pairs.size(); i++) {
135                     auto& pair = pairs[i];
136                     RegType source = pair.first;
137                     RegType dest = pair.second;
138                     if (freeDestinations.get(dest)) {
139                         move(source, dest);
140                         pairs.remove(i);
141                         madeMove = true;
142                         break;
143                     }
144                 }
145                 ASSERT_UNUSED(madeMove, madeMove);
146                 continue;
147             }
148
149             ASSERT(numUniqueDests() == numUniqueSources());
150             ASSERT(numUniqueDests() == pairs.size());
151             // The set of source and destination registers are equivalent sets. This means we don't have
152             // any free destination registers that won't also clobber a source. We get around this by
153             // exchanging registers.
154
155             RegType source = pairs[0].first;
156             RegType dest = pairs[0].second;
157             swap(source, dest);
158             pairs.remove(0);
159
160             RegType newSource = source;
161             for (auto& pair : pairs) {
162                 RegType source = pair.first;
163                 if (source == dest) {
164                     pair.first = newSource;
165                     break;
166                 }
167             }
168
169             // We may have introduced pairs that have the same source and destination. Remove those now.
170             for (unsigned i = 0; i < pairs.size(); i++) {
171                 auto& pair = pairs[i];
172                 if (pair.first == pair.second) {
173                     pairs.remove(i);
174                     i--;
175                 }
176             }
177         }
178     }
179
180     template<typename RegType>
181     using InfoTypeForReg = decltype(toInfoFromReg(RegType(-1)));
182
183     // extraPoke is used to track 64-bit argument types passed on the stack.
184     template<unsigned numGPRArgs, unsigned numGPRSources, unsigned numFPRArgs, unsigned numFPRSources, unsigned extraPoke>
185     struct ArgCollection {
186         ArgCollection()
187         {
188             gprSources.fill(InvalidGPRReg);
189             gprDestinations.fill(InvalidGPRReg);
190             fprSources.fill(InvalidFPRReg);
191             fprDestinations.fill(InvalidFPRReg);
192         }
193
194         template<unsigned a, unsigned b, unsigned c, unsigned d, unsigned e>
195         ArgCollection(ArgCollection<a, b, c, d, e>& other)
196         {
197             gprSources = other.gprSources;
198             gprDestinations = other.gprDestinations;
199             fprSources = other.fprSources;
200             fprDestinations = other.fprDestinations;
201         }
202
203         ArgCollection<numGPRArgs + 1, numGPRSources + 1, numFPRArgs, numFPRSources, extraPoke> pushRegArg(GPRReg argument, GPRReg destination)
204         {
205             ArgCollection<numGPRArgs + 1, numGPRSources + 1, numFPRArgs, numFPRSources, extraPoke> result(*this);
206
207             result.gprSources[numGPRSources] = argument;
208             result.gprDestinations[numGPRSources] = destination;
209             return result;
210         }
211
212         ArgCollection<numGPRArgs, numGPRSources, numFPRArgs + 1, numFPRSources + 1, extraPoke> pushRegArg(FPRReg argument, FPRReg destination)
213         {
214             ArgCollection<numGPRArgs, numGPRSources, numFPRArgs + 1, numFPRSources + 1, extraPoke> result(*this);
215
216             result.fprSources[numFPRSources] = argument;
217             result.fprDestinations[numFPRSources] = destination;
218             return result;
219         }
220
221         ArgCollection<numGPRArgs + 1, numGPRSources, numFPRArgs, numFPRSources, extraPoke> addGPRArg()
222         {
223             return ArgCollection<numGPRArgs + 1, numGPRSources, numFPRArgs, numFPRSources, extraPoke>(*this);
224         }
225
226         ArgCollection<numGPRArgs + 1, numGPRSources, numFPRArgs, numFPRSources, extraPoke> addStackArg(GPRReg)
227         {
228             return ArgCollection<numGPRArgs + 1, numGPRSources, numFPRArgs, numFPRSources, extraPoke>(*this);
229         }
230
231         ArgCollection<numGPRArgs, numGPRSources, numFPRArgs + 1, numFPRSources, extraPoke> addStackArg(FPRReg)
232         {
233             return ArgCollection<numGPRArgs, numGPRSources, numFPRArgs + 1, numFPRSources, extraPoke>(*this);
234         }
235
236         ArgCollection<numGPRArgs, numGPRSources, numFPRArgs, numFPRSources, extraPoke + 1> addPoke()
237         {
238             return ArgCollection<numGPRArgs, numGPRSources, numFPRArgs, numFPRSources, extraPoke + 1>(*this);
239         }
240
241
242         unsigned argCount(GPRReg) { return numGPRArgs; }
243         unsigned argCount(FPRReg) { return numFPRArgs; }
244
245         std::array<GPRReg, GPRInfo::numberOfRegisters> gprSources;
246         std::array<GPRReg, GPRInfo::numberOfRegisters> gprDestinations;
247         std::array<FPRReg, FPRInfo::numberOfRegisters> fprSources;
248         std::array<FPRReg, FPRInfo::numberOfRegisters> fprDestinations;
249     };
250
251 #if COMPILER(MSVC)
252 #pragma warning(push)
253 #pragma warning(disable: 4701)
254 #endif
255
256     template<unsigned TargetSize, typename RegType>
257     std::array<RegType, TargetSize> clampArrayToSize(std::array<RegType, InfoTypeForReg<RegType>::numberOfRegisters> sourceArray)
258     {
259         static_assert(TargetSize <= sourceArray.size(), "TargetSize is bigger than source.size()");
260         RELEASE_ASSERT(TargetSize <= InfoTypeForReg<RegType>::numberOfRegisters);
261
262         std::array<RegType, TargetSize> result;
263
264         for (unsigned i = 0; i < TargetSize; i++) {
265             ASSERT(sourceArray[i] != InfoTypeForReg<RegType>::InvalidIndex);
266             result[i] = sourceArray[i];
267         }
268
269         return result;
270     }
271
272 #if COMPILER(MSVC)
273 #pragma warning(pop)
274 #endif
275
276     template<typename ArgType>
277     ALWAYS_INLINE void pokeForArgument(ArgType arg, unsigned currentGPRArgument, unsigned currentFPRArgument, unsigned extraPoke)
278     {
279         // Clang claims that it cannot find the symbol for FPRReg/GPRReg::numberOfArgumentRegisters when they are passed directly to std::max... seems like a bug
280         unsigned numberOfFPArgumentRegisters = FPRInfo::numberOfArgumentRegisters;
281         unsigned numberOfGPArgumentRegisters = GPRInfo::numberOfArgumentRegisters;
282         ASSERT(currentGPRArgument >= GPRInfo::numberOfArgumentRegisters || currentFPRArgument >= FPRInfo::numberOfArgumentRegisters);
283
284         unsigned pokeOffset = POKE_ARGUMENT_OFFSET + extraPoke;
285         pokeOffset += std::max(currentGPRArgument, numberOfGPArgumentRegisters) - numberOfGPArgumentRegisters;
286         pokeOffset += std::max(currentFPRArgument, numberOfFPArgumentRegisters) - numberOfFPArgumentRegisters;
287         poke(arg, pokeOffset);
288     }
289
290     // In the auto-calling convention code below the order of operations is:
291     //    1) spill arguments to stack slots
292     //    2) shuffle incomming argument values in registers to argument registers
293     //    3) fill immediate values to argument registers
294     // To do this, we recurse forwards through our args collecting argument values in registers and spilling stack slots.
295     // when we run out of args we then run our shuffling code to relocate registers. Finally, as we unwind from our
296     // recursion we can fill immediates.
297
298 #define CURRENT_ARGUMENT_TYPE typename FunctionTraits<OperationType>::template ArgumentType<numGPRArgs + numFPRArgs>
299
300 #if USE(JSVALUE64)
301
302     template<typename OperationType, unsigned numGPRArgs, unsigned numGPRSources, unsigned numFPRArgs, unsigned numFPRSources, unsigned extraPoke, typename RegType, typename... Args>
303     ALWAYS_INLINE void marshallArgumentRegister(ArgCollection<numGPRArgs, numGPRSources, numFPRArgs, numFPRSources, extraPoke> argSourceRegs, RegType arg, Args... args)
304     {
305         using InfoType = InfoTypeForReg<RegType>;
306         unsigned numArgRegisters = InfoType::numberOfArgumentRegisters;
307         unsigned currentArgCount = argSourceRegs.argCount(arg);
308         if (currentArgCount < numArgRegisters) {
309             auto updatedArgSourceRegs = argSourceRegs.pushRegArg(arg, InfoType::toArgumentRegister(currentArgCount));
310             setupArgumentsImpl<OperationType>(updatedArgSourceRegs, args...);
311             return;
312         }
313
314         pokeForArgument(arg, numGPRArgs, numFPRArgs, extraPoke);
315         setupArgumentsImpl<OperationType>(argSourceRegs.addStackArg(arg), args...);
316     }
317
318     template<typename OperationType, unsigned numGPRArgs, unsigned numGPRSources, unsigned numFPRArgs, unsigned numFPRSources, unsigned extraPoke, typename... Args>
319     ALWAYS_INLINE void setupArgumentsImpl(ArgCollection<numGPRArgs, numGPRSources, numFPRArgs, numFPRSources, extraPoke> argSourceRegs, FPRReg arg, Args... args)
320     {
321         static_assert(std::is_same<CURRENT_ARGUMENT_TYPE, double>::value, "We should only be passing FPRRegs to a double");
322         marshallArgumentRegister<OperationType>(argSourceRegs, arg, args...);
323     }
324
325     template<typename OperationType, unsigned numGPRArgs, unsigned numGPRSources, unsigned numFPRArgs, unsigned numFPRSources, unsigned extraPoke, typename... Args>
326     ALWAYS_INLINE void setupArgumentsImpl(ArgCollection<numGPRArgs, numGPRSources, numFPRArgs, numFPRSources, extraPoke> argSourceRegs, GPRReg arg, Args... args)
327     {
328         marshallArgumentRegister<OperationType>(argSourceRegs, arg, args...);
329     }
330
331     template<typename OperationType, unsigned numGPRArgs, unsigned numGPRSources, unsigned numFPRArgs, unsigned numFPRSources, unsigned extraPoke, typename... Args>
332     ALWAYS_INLINE void setupArgumentsImpl(ArgCollection<numGPRArgs, numGPRSources, numFPRArgs, numFPRSources, extraPoke> argSourceRegs, JSValueRegs arg, Args... args)
333     {
334         marshallArgumentRegister<OperationType>(argSourceRegs, arg.gpr(), args...);
335     }
336
337 #else // USE(JSVALUE64)
338
339     // These functions are a hack for X86 since it has no argument gprs...
340
341     template<typename OperationType, unsigned numGPRArgs, unsigned numGPRSources, unsigned numFPRArgs, unsigned numFPRSources, unsigned extraPoke, typename... Args>
342     ALWAYS_INLINE void setupArgumentsImpl(ArgCollection<numGPRArgs, numGPRSources, numFPRArgs, numFPRSources, extraPoke> argSourceRegs, FPRReg arg, Args... args)
343     {
344         static_assert(std::is_same<CURRENT_ARGUMENT_TYPE, double>::value, "We should only be passing FPRRegs to a double");
345         pokeForArgument(arg, numGPRArgs, numFPRArgs, extraPoke);
346         setupArgumentsImpl<OperationType>(argSourceRegs.addStackArg(arg).addPoke(), args...);
347     }
348
349     template<typename OperationType, unsigned numGPRArgs, unsigned numGPRSources, unsigned numFPRArgs, unsigned numFPRSources, unsigned extraPoke, typename... Args>
350     ALWAYS_INLINE std::enable_if_t<sizeof(CURRENT_ARGUMENT_TYPE) <= 4>
351     setupArgumentsImpl(ArgCollection<numGPRArgs, numGPRSources, numFPRArgs, numFPRSources, extraPoke> argSourceRegs, GPRReg arg, Args... args)
352     {
353         pokeForArgument(arg, numGPRArgs, numFPRArgs, extraPoke);
354         setupArgumentsImpl<OperationType>(argSourceRegs.addGPRArg(), args...);
355     }
356
357     template<typename OperationType, unsigned numGPRArgs, unsigned numGPRSources, unsigned numFPRArgs, unsigned numFPRSources, unsigned extraPoke, typename... Args>
358     ALWAYS_INLINE std::enable_if_t<std::is_same<CURRENT_ARGUMENT_TYPE, EncodedJSValue>::value>
359     setupArgumentsImpl(ArgCollection<numGPRArgs, numGPRSources, numFPRArgs, numFPRSources, extraPoke> argSourceRegs, JSValue::JSCellTag, GPRReg payload, Args... args)
360     {
361         pokeForArgument(payload, numGPRArgs, numFPRArgs, extraPoke);
362         pokeForArgument(TrustedImm32(JSValue::CellTag), numGPRArgs, numFPRArgs, extraPoke + 1);
363         setupArgumentsImpl<OperationType>(argSourceRegs.addGPRArg().addPoke(), args...);
364     }
365
366     template<typename OperationType, unsigned numGPRArgs, unsigned numGPRSources, unsigned numFPRArgs, unsigned numFPRSources, unsigned extraPoke, typename... Args>
367     ALWAYS_INLINE std::enable_if_t<std::is_same<CURRENT_ARGUMENT_TYPE, EncodedJSValue>::value>
368     setupArgumentsImpl(ArgCollection<numGPRArgs, numGPRSources, numFPRArgs, numFPRSources, extraPoke> argSourceRegs, JSValue::JSCellTag, TrustedImmPtr payload, Args... args)
369     {
370         pokeForArgument(payload, numGPRArgs, numFPRArgs, extraPoke);
371         pokeForArgument(TrustedImm32(JSValue::CellTag), numGPRArgs, numFPRArgs, extraPoke + 1);
372         setupArgumentsImpl<OperationType>(argSourceRegs.addGPRArg().addPoke(), args...);
373     }
374
375     template<typename OperationType, unsigned numGPRArgs, unsigned numGPRSources, unsigned numFPRArgs, unsigned numFPRSources, unsigned extraPoke, typename... Args>
376     ALWAYS_INLINE std::enable_if_t<std::is_same<CURRENT_ARGUMENT_TYPE, EncodedJSValue>::value>
377     setupArgumentsImpl(ArgCollection<numGPRArgs, numGPRSources, numFPRArgs, numFPRSources, extraPoke> argSourceRegs, JSValueRegs arg, Args... args)
378     {
379         pokeForArgument(arg.payloadGPR(), numGPRArgs, numFPRArgs, extraPoke);
380         pokeForArgument(arg.tagGPR(), numGPRArgs, numFPRArgs, extraPoke + 1);
381         setupArgumentsImpl<OperationType>(argSourceRegs.addGPRArg().addPoke(), args...);
382     }
383
384 #endif // USE(JSVALUE64)
385
386     template<typename OperationType, unsigned numGPRArgs, unsigned numGPRSources, unsigned numFPRArgs, unsigned numFPRSources, unsigned extraPoke, typename Arg, typename... Args>
387     ALWAYS_INLINE std::enable_if_t<
388         std::is_base_of<TrustedImm, Arg>::value
389         || std::is_convertible<Arg, TrustedImm>::value> // We have this since DFGSpeculativeJIT has it's own implementation of TrustedImmPtr
390     setupArgumentsImpl(ArgCollection<numGPRArgs, numGPRSources, numFPRArgs, numFPRSources, extraPoke> argSourceRegs, Arg arg, Args... args)
391     {
392         // Right now this only supports non-floating point immediate arguments since we never call operations with non-register values.
393         // If we ever needed to support immediate floating point arguments we would need to duplicate this logic for both types, which sounds
394         // gross so it's probably better to do that marshalling before the call operation...
395         static_assert(!std::is_floating_point<CURRENT_ARGUMENT_TYPE>::value, "We don't support immediate floats/doubles in setupArguments");
396         auto numArgRegisters = GPRInfo::numberOfArgumentRegisters;
397         if (numGPRArgs < numArgRegisters) {
398             setupArgumentsImpl<OperationType>(argSourceRegs.addGPRArg(), args...);
399             move(arg, GPRInfo::toArgumentRegister(numGPRArgs));
400             return;
401         }
402
403         pokeForArgument(arg, numGPRArgs, numFPRArgs, extraPoke);
404         setupArgumentsImpl<OperationType>(argSourceRegs.addGPRArg(), args...);
405     }
406
407     template<typename OperationType, unsigned numGPRArgs, unsigned numGPRSources, unsigned numFPRArgs, unsigned numFPRSources, unsigned extraPoke, typename Arg, typename... Args>
408     ALWAYS_INLINE std::enable_if_t<
409         std::is_same<CURRENT_ARGUMENT_TYPE, Arg>::value
410         && std::is_integral<CURRENT_ARGUMENT_TYPE>::value
411         && (sizeof(CURRENT_ARGUMENT_TYPE) <= 4)>
412     setupArgumentsImpl(ArgCollection<numGPRArgs, numGPRSources, numFPRArgs, numFPRSources, extraPoke> argSourceRegs, Arg arg, Args... args)
413     {
414         setupArgumentsImpl<OperationType>(argSourceRegs, TrustedImm32(arg), args...);
415     }
416
417     template<typename OperationType, unsigned numGPRArgs, unsigned numGPRSources, unsigned numFPRArgs, unsigned numFPRSources, unsigned extraPoke, typename Arg, typename... Args>
418     ALWAYS_INLINE std::enable_if_t<
419         std::is_same<CURRENT_ARGUMENT_TYPE, Arg>::value
420         && std::is_integral<CURRENT_ARGUMENT_TYPE>::value
421         && (sizeof(CURRENT_ARGUMENT_TYPE) == 8)>
422     setupArgumentsImpl(ArgCollection<numGPRArgs, numGPRSources, numFPRArgs, numFPRSources, extraPoke> argSourceRegs, Arg arg, Args... args)
423     {
424         setupArgumentsImpl<OperationType>(argSourceRegs, TrustedImm64(arg), args...);
425     }
426
427     template<typename OperationType, unsigned numGPRArgs, unsigned numGPRSources, unsigned numFPRArgs, unsigned numFPRSources, unsigned extraPoke, typename Arg, typename... Args>
428     ALWAYS_INLINE std::enable_if_t<
429         std::is_pointer<CURRENT_ARGUMENT_TYPE>::value
430         && ((std::is_pointer<Arg>::value && std::is_convertible<std::remove_const_t<std::remove_pointer_t<Arg>>*, CURRENT_ARGUMENT_TYPE>::value)
431             || std::is_same<Arg, std::nullptr_t>::value)>
432     setupArgumentsImpl(ArgCollection<numGPRArgs, numGPRSources, numFPRArgs, numFPRSources, extraPoke> argSourceRegs, Arg arg, Args... args)
433     {
434         setupArgumentsImpl<OperationType>(argSourceRegs, TrustedImmPtr(arg), args...);
435     }
436
437     // Special case DFG::RegisteredStructure because it's really annoying to deal with otherwise...
438     template<typename OperationType, unsigned numGPRArgs, unsigned numGPRSources, unsigned numFPRArgs, unsigned numFPRSources, unsigned extraPoke, typename Arg, typename... Args>
439     ALWAYS_INLINE std::enable_if_t<
440         std::is_same<CURRENT_ARGUMENT_TYPE, Structure*>::value
441         && std::is_same<Arg, DFG::RegisteredStructure>::value>
442     setupArgumentsImpl(ArgCollection<numGPRArgs, numGPRSources, numFPRArgs, numFPRSources, extraPoke> argSourceRegs, Arg arg, Args... args)
443     {
444         setupArgumentsImpl<OperationType>(argSourceRegs, TrustedImmPtr(arg.get()), args...);
445     }
446
447 #undef CURRENT_ARGUMENT_TYPE
448
449     // Base case; set up the argument registers.
450     template<typename OperationType, unsigned numGPRArgs, unsigned numGPRSources, unsigned numFPRArgs, unsigned numFPRSources, unsigned extraPoke>
451     ALWAYS_INLINE void setupArgumentsImpl(ArgCollection<numGPRArgs, numGPRSources, numFPRArgs, numFPRSources, extraPoke> argSourceRegs)
452     {
453         static_assert(FunctionTraits<OperationType>::arity == numGPRArgs + numFPRArgs, "One last sanity check");
454         static_assert(FunctionTraits<OperationType>::cCallArity() == numGPRArgs + numFPRArgs + extraPoke, "Check the CCall arity");
455         setupStubArgs<numGPRSources, GPRReg>(clampArrayToSize<numGPRSources, GPRReg>(argSourceRegs.gprDestinations), clampArrayToSize<numGPRSources, GPRReg>(argSourceRegs.gprSources));
456
457         setupStubArgs<numFPRSources, FPRReg>(clampArrayToSize<numFPRSources, FPRReg>(argSourceRegs.fprDestinations), clampArrayToSize<numFPRSources, FPRReg>(argSourceRegs.fprSources));
458     }
459
460 public:
461
462 #define FIRST_ARGUMENT_TYPE typename FunctionTraits<OperationType>::template ArgumentType<0>
463
464     template<typename OperationType, typename... Args>
465     ALWAYS_INLINE std::enable_if_t<std::is_same<FIRST_ARGUMENT_TYPE, ExecState*>::value> setupArguments(Args... args)
466     {
467 #if USE(JSVALUE64)
468         // This only really works for 64-bit since jsvalue regs mess things up for 32-bit...
469         static_assert(FunctionTraits<OperationType>::cCallArity() == sizeof...(Args) + 1, "Basic sanity check");
470 #endif
471         setupArgumentsImpl<OperationType, 0, 0, 0, 0, 0>(ArgCollection<0, 0, 0, 0, 0>(), GPRInfo::callFrameRegister, args...);
472     }
473
474     template<typename OperationType, typename... Args>
475     ALWAYS_INLINE std::enable_if_t<!std::is_same<FIRST_ARGUMENT_TYPE, ExecState*>::value> setupArguments(Args... args)
476     {
477 #if USE(JSVALUE64)
478         // This only really works for 64-bit since jsvalue regs mess things up for 32-bit...
479         static_assert(FunctionTraits<OperationType>::cCallArity() == sizeof...(Args), "Basic sanity check");
480 #endif
481         setupArgumentsImpl<OperationType, 0, 0, 0, 0, 0>(ArgCollection<0, 0, 0, 0, 0>(), args...);
482     }
483
484 #undef FIRST_ARGUMENT_TYPE
485
486     void setupResults(GPRReg destA, GPRReg destB)
487     {
488         GPRReg srcA = GPRInfo::returnValueGPR;
489         GPRReg srcB = GPRInfo::returnValueGPR2;
490
491         if (destA == InvalidGPRReg)
492             move(srcB, destB);
493         else if (destB == InvalidGPRReg)
494             move(srcA, destA);
495         else if (srcB != destA) {
496             // Handle the easy cases - two simple moves.
497             move(srcA, destA);
498             move(srcB, destB);
499         } else if (srcA != destB) {
500             // Handle the non-swap case - just put srcB in place first.
501             move(srcB, destB);
502             move(srcA, destA);
503         } else
504             swap(destA, destB);
505     }
506     
507     void setupResults(JSValueRegs regs)
508     {
509 #if USE(JSVALUE64)
510         move(GPRInfo::returnValueGPR, regs.gpr());
511 #else
512         setupResults(regs.payloadGPR(), regs.tagGPR());
513 #endif
514     }
515     
516     void jumpToExceptionHandler(VM& vm)
517     {
518         // genericUnwind() leaves the handler CallFrame* in vm->callFrameForCatch,
519         // and the address of the handler in vm->targetMachinePCForThrow.
520         loadPtr(&vm.targetMachinePCForThrow, GPRInfo::regT1);
521         jump(GPRInfo::regT1);
522     }
523
524     void prepareForTailCallSlow(GPRReg calleeGPR = InvalidGPRReg)
525     {
526         GPRReg temp1 = calleeGPR == GPRInfo::regT0 ? GPRInfo::regT3 : GPRInfo::regT0;
527         GPRReg temp2 = calleeGPR == GPRInfo::regT1 ? GPRInfo::regT3 : GPRInfo::regT1;
528         GPRReg temp3 = calleeGPR == GPRInfo::regT2 ? GPRInfo::regT3 : GPRInfo::regT2;
529
530         GPRReg newFramePointer = temp1;
531         GPRReg newFrameSizeGPR = temp2;
532         {
533             // The old frame size is its number of arguments (or number of
534             // parameters in case of arity fixup), plus the frame header size,
535             // aligned
536             GPRReg oldFrameSizeGPR = temp2;
537             {
538                 GPRReg argCountGPR = oldFrameSizeGPR;
539                 load32(Address(framePointerRegister, CallFrameSlot::argumentCount * static_cast<int>(sizeof(Register)) + PayloadOffset), argCountGPR);
540
541                 {
542                     GPRReg numParametersGPR = temp1;
543                     {
544                         GPRReg codeBlockGPR = numParametersGPR;
545                         loadPtr(Address(framePointerRegister, CallFrameSlot::codeBlock * static_cast<int>(sizeof(Register))), codeBlockGPR);
546                         load32(Address(codeBlockGPR, CodeBlock::offsetOfNumParameters()), numParametersGPR);
547                     }
548
549                     ASSERT(numParametersGPR != argCountGPR);
550                     Jump argumentCountWasNotFixedUp = branch32(BelowOrEqual, numParametersGPR, argCountGPR);
551                     move(numParametersGPR, argCountGPR);
552                     argumentCountWasNotFixedUp.link(this);
553                 }
554
555                 add32(TrustedImm32(stackAlignmentRegisters() + CallFrame::headerSizeInRegisters - 1), argCountGPR, oldFrameSizeGPR);
556                 and32(TrustedImm32(-stackAlignmentRegisters()), oldFrameSizeGPR);
557                 // We assume < 2^28 arguments
558                 mul32(TrustedImm32(sizeof(Register)), oldFrameSizeGPR, oldFrameSizeGPR);
559             }
560
561             // The new frame pointer is at framePointer + oldFrameSize - newFrameSize
562             ASSERT(newFramePointer != oldFrameSizeGPR);
563             addPtr(framePointerRegister, oldFrameSizeGPR, newFramePointer);
564
565             // The new frame size is just the number of arguments plus the
566             // frame header size, aligned
567             ASSERT(newFrameSizeGPR != newFramePointer);
568             load32(Address(stackPointerRegister, CallFrameSlot::argumentCount * static_cast<int>(sizeof(Register)) + PayloadOffset - sizeof(CallerFrameAndPC)),
569                 newFrameSizeGPR);
570             add32(TrustedImm32(stackAlignmentRegisters() + CallFrame::headerSizeInRegisters - 1), newFrameSizeGPR);
571             and32(TrustedImm32(-stackAlignmentRegisters()), newFrameSizeGPR);
572             // We assume < 2^28 arguments
573             mul32(TrustedImm32(sizeof(Register)), newFrameSizeGPR, newFrameSizeGPR);
574         }
575
576         GPRReg tempGPR = temp3;
577         ASSERT(tempGPR != newFramePointer && tempGPR != newFrameSizeGPR);
578
579         // We don't need the current frame beyond this point. Masquerade as our
580         // caller.
581 #if CPU(ARM) || CPU(ARM64)
582         loadPtr(Address(framePointerRegister, sizeof(void*)), linkRegister);
583         subPtr(TrustedImm32(2 * sizeof(void*)), newFrameSizeGPR);
584 #elif CPU(MIPS)
585         loadPtr(Address(framePointerRegister, sizeof(void*)), returnAddressRegister);
586         subPtr(TrustedImm32(2 * sizeof(void*)), newFrameSizeGPR);
587 #elif CPU(X86) || CPU(X86_64)
588         loadPtr(Address(framePointerRegister, sizeof(void*)), tempGPR);
589         push(tempGPR);
590         subPtr(TrustedImm32(sizeof(void*)), newFrameSizeGPR);
591 #else
592         UNREACHABLE_FOR_PLATFORM();
593 #endif
594         subPtr(newFrameSizeGPR, newFramePointer);
595         loadPtr(Address(framePointerRegister), framePointerRegister);
596
597
598         // We need to move the newFrameSizeGPR slots above the stack pointer by
599         // newFramePointer registers. We use pointer-sized chunks.
600         MacroAssembler::Label copyLoop(label());
601
602         subPtr(TrustedImm32(sizeof(void*)), newFrameSizeGPR);
603         loadPtr(BaseIndex(stackPointerRegister, newFrameSizeGPR, TimesOne), tempGPR);
604         storePtr(tempGPR, BaseIndex(newFramePointer, newFrameSizeGPR, TimesOne));
605
606         branchTest32(MacroAssembler::NonZero, newFrameSizeGPR).linkTo(copyLoop, this);
607
608         // Ready for a jump!
609         move(newFramePointer, stackPointerRegister);
610     }
611     
612     // These operations clobber all volatile registers. They assume that there is room on the top of
613     // stack to marshall call arguments.
614     void logShadowChickenProloguePacket(GPRReg shadowPacket, GPRReg scratch1, GPRReg scope);
615     void logShadowChickenTailPacket(GPRReg shadowPacket, JSValueRegs thisRegs, GPRReg scope, CodeBlock*, CallSiteIndex);
616     // Leaves behind a pointer to the Packet we should write to in shadowPacket.
617     void ensureShadowChickenPacket(VM&, GPRReg shadowPacket, GPRReg scratch1NonArgGPR, GPRReg scratch2);
618 };
619
620 } // namespace JSC
621
622 #endif // ENABLE(JIT)