2 * Copyright (C) 2011, 2015-2016 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
30 #include "AssemblyHelpers.h"
33 #include "StackAlignment.h"
34 #include <wtf/FunctionTraits.h>
38 #if CPU(MIPS) || (OS(WINDOWS) && CPU(X86_64))
39 #define POKE_ARGUMENT_OFFSET 4
41 #define POKE_ARGUMENT_OFFSET 0
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),
49 #define EABI_32BIT_DUMMY_ARG
55 class RegisteredStructure;
58 class CCallHelpers : public AssemblyHelpers {
60 CCallHelpers(CodeBlock* codeBlock = 0)
61 : AssemblyHelpers(codeBlock)
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)
71 unsigned numberOfRegs = GPRInfo::numberOfArgumentRegisters; // Disguise the constant from clang's tautological compare warning.
72 if (argumentIndex < numberOfRegs) {
73 functor(GPRInfo::toArgumentRegister(argumentIndex));
77 functor(GPRInfo::nonArgGPR0);
78 poke(GPRInfo::nonArgGPR0, POKE_ARGUMENT_OFFSET + argumentIndex - GPRInfo::numberOfArgumentRegisters);
83 template<unsigned NumberOfRegisters, typename RegType>
84 ALWAYS_INLINE void setupStubArgs(std::array<RegType, NumberOfRegisters> destinations, std::array<RegType, NumberOfRegisters> sources)
86 if (!ASSERT_DISABLED) {
88 for (RegType dest : destinations)
90 ASSERT_WITH_MESSAGE(set.numberOfSetRegisters() == NumberOfRegisters, "Destinations should not be aliased.");
93 typedef std::pair<RegType, RegType> RegPair;
94 Vector<RegPair, NumberOfRegisters> pairs;
96 for (unsigned i = 0; i < NumberOfRegisters; ++i) {
97 if (sources[i] != destinations[i])
98 pairs.append(std::make_pair(sources[i], destinations[i]));
102 auto numUniqueSources = [&] () -> unsigned {
104 for (auto& pair : pairs) {
105 RegType source = pair.first;
108 return set.numberOfSetRegisters();
111 auto numUniqueDests = [&] () -> unsigned {
113 for (auto& pair : pairs) {
114 RegType dest = pair.second;
117 return set.numberOfSetRegisters();
121 while (pairs.size()) {
122 RegisterSet freeDestinations;
123 for (auto& pair : pairs) {
124 RegType dest = pair.second;
125 freeDestinations.set(dest);
127 for (auto& pair : pairs) {
128 RegType source = pair.first;
129 freeDestinations.clear(source);
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)) {
145 ASSERT_UNUSED(madeMove, madeMove);
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.
155 RegType source = pairs[0].first;
156 RegType dest = pairs[0].second;
160 RegType newSource = source;
161 for (auto& pair : pairs) {
162 RegType source = pair.first;
163 if (source == dest) {
164 pair.first = newSource;
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) {
180 template<typename RegType>
181 using InfoTypeForReg = decltype(toInfoFromReg(RegType(-1)));
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 {
188 gprSources.fill(InvalidGPRReg);
189 gprDestinations.fill(InvalidGPRReg);
190 fprSources.fill(InvalidFPRReg);
191 fprDestinations.fill(InvalidFPRReg);
194 template<unsigned a, unsigned b, unsigned c, unsigned d, unsigned e>
195 ArgCollection(ArgCollection<a, b, c, d, e>& other)
197 gprSources = other.gprSources;
198 gprDestinations = other.gprDestinations;
199 fprSources = other.fprSources;
200 fprDestinations = other.fprDestinations;
203 ArgCollection<numGPRArgs + 1, numGPRSources + 1, numFPRArgs, numFPRSources, extraPoke> pushRegArg(GPRReg argument, GPRReg destination)
205 ArgCollection<numGPRArgs + 1, numGPRSources + 1, numFPRArgs, numFPRSources, extraPoke> result(*this);
207 result.gprSources[numGPRSources] = argument;
208 result.gprDestinations[numGPRSources] = destination;
212 ArgCollection<numGPRArgs, numGPRSources, numFPRArgs + 1, numFPRSources + 1, extraPoke> pushRegArg(FPRReg argument, FPRReg destination)
214 ArgCollection<numGPRArgs, numGPRSources, numFPRArgs + 1, numFPRSources + 1, extraPoke> result(*this);
216 result.fprSources[numFPRSources] = argument;
217 result.fprDestinations[numFPRSources] = destination;
221 ArgCollection<numGPRArgs + 1, numGPRSources, numFPRArgs, numFPRSources, extraPoke> addGPRArg()
223 return ArgCollection<numGPRArgs + 1, numGPRSources, numFPRArgs, numFPRSources, extraPoke>(*this);
226 ArgCollection<numGPRArgs + 1, numGPRSources, numFPRArgs, numFPRSources, extraPoke> addStackArg(GPRReg)
228 return ArgCollection<numGPRArgs + 1, numGPRSources, numFPRArgs, numFPRSources, extraPoke>(*this);
231 ArgCollection<numGPRArgs, numGPRSources, numFPRArgs + 1, numFPRSources, extraPoke> addStackArg(FPRReg)
233 return ArgCollection<numGPRArgs, numGPRSources, numFPRArgs + 1, numFPRSources, extraPoke>(*this);
236 ArgCollection<numGPRArgs, numGPRSources, numFPRArgs, numFPRSources, extraPoke + 1> addPoke()
238 return ArgCollection<numGPRArgs, numGPRSources, numFPRArgs, numFPRSources, extraPoke + 1>(*this);
242 unsigned argCount(GPRReg) { return numGPRArgs; }
243 unsigned argCount(FPRReg) { return numFPRArgs; }
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;
252 #pragma warning(push)
253 #pragma warning(disable: 4701)
256 template<unsigned TargetSize, typename RegType>
257 std::array<RegType, TargetSize> clampArrayToSize(std::array<RegType, InfoTypeForReg<RegType>::numberOfRegisters> sourceArray)
259 static_assert(TargetSize <= sourceArray.size(), "TargetSize is bigger than source.size()");
260 RELEASE_ASSERT(TargetSize <= InfoTypeForReg<RegType>::numberOfRegisters);
262 std::array<RegType, TargetSize> result;
264 for (unsigned i = 0; i < TargetSize; i++) {
265 ASSERT(sourceArray[i] != InfoTypeForReg<RegType>::InvalidIndex);
266 result[i] = sourceArray[i];
276 template<typename ArgType>
277 ALWAYS_INLINE void pokeForArgument(ArgType arg, unsigned currentGPRArgument, unsigned currentFPRArgument, unsigned extraPoke)
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);
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);
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.
298 #define CURRENT_ARGUMENT_TYPE typename FunctionTraits<OperationType>::template ArgumentType<numGPRArgs + numFPRArgs>
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)
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...);
314 pokeForArgument(arg, numGPRArgs, numFPRArgs, extraPoke);
315 setupArgumentsImpl<OperationType>(argSourceRegs.addStackArg(arg), args...);
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)
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...);
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)
328 marshallArgumentRegister<OperationType>(argSourceRegs, arg, args...);
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)
334 marshallArgumentRegister<OperationType>(argSourceRegs, arg.gpr(), args...);
337 #else // USE(JSVALUE64)
339 // These functions are a hack for X86 since it has no argument gprs...
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)
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...);
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)
353 pokeForArgument(arg, numGPRArgs, numFPRArgs, extraPoke);
354 setupArgumentsImpl<OperationType>(argSourceRegs.addGPRArg(), args...);
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)
361 pokeForArgument(payload, numGPRArgs, numFPRArgs, extraPoke);
362 pokeForArgument(TrustedImm32(JSValue::CellTag), numGPRArgs, numFPRArgs, extraPoke + 1);
363 setupArgumentsImpl<OperationType>(argSourceRegs.addGPRArg().addPoke(), args...);
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)
370 pokeForArgument(payload, numGPRArgs, numFPRArgs, extraPoke);
371 pokeForArgument(TrustedImm32(JSValue::CellTag), numGPRArgs, numFPRArgs, extraPoke + 1);
372 setupArgumentsImpl<OperationType>(argSourceRegs.addGPRArg().addPoke(), args...);
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)
379 pokeForArgument(arg.payloadGPR(), numGPRArgs, numFPRArgs, extraPoke);
380 pokeForArgument(arg.tagGPR(), numGPRArgs, numFPRArgs, extraPoke + 1);
381 setupArgumentsImpl<OperationType>(argSourceRegs.addGPRArg().addPoke(), args...);
384 #endif // USE(JSVALUE64)
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)
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));
403 pokeForArgument(arg, numGPRArgs, numFPRArgs, extraPoke);
404 setupArgumentsImpl<OperationType>(argSourceRegs.addGPRArg(), args...);
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)
414 setupArgumentsImpl<OperationType>(argSourceRegs, TrustedImm32(arg), args...);
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)
424 setupArgumentsImpl<OperationType>(argSourceRegs, TrustedImm64(arg), args...);
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)
434 setupArgumentsImpl<OperationType>(argSourceRegs, TrustedImmPtr(arg), args...);
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)
444 setupArgumentsImpl<OperationType>(argSourceRegs, TrustedImmPtr(arg.get()), args...);
447 #undef CURRENT_ARGUMENT_TYPE
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)
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));
457 setupStubArgs<numFPRSources, FPRReg>(clampArrayToSize<numFPRSources, FPRReg>(argSourceRegs.fprDestinations), clampArrayToSize<numFPRSources, FPRReg>(argSourceRegs.fprSources));
462 #define FIRST_ARGUMENT_TYPE typename FunctionTraits<OperationType>::template ArgumentType<0>
464 template<typename OperationType, typename... Args>
465 ALWAYS_INLINE std::enable_if_t<std::is_same<FIRST_ARGUMENT_TYPE, ExecState*>::value> setupArguments(Args... args)
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");
471 setupArgumentsImpl<OperationType, 0, 0, 0, 0, 0>(ArgCollection<0, 0, 0, 0, 0>(), GPRInfo::callFrameRegister, args...);
474 template<typename OperationType, typename... Args>
475 ALWAYS_INLINE std::enable_if_t<!std::is_same<FIRST_ARGUMENT_TYPE, ExecState*>::value> setupArguments(Args... args)
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");
481 setupArgumentsImpl<OperationType, 0, 0, 0, 0, 0>(ArgCollection<0, 0, 0, 0, 0>(), args...);
484 #undef FIRST_ARGUMENT_TYPE
486 void setupResults(GPRReg destA, GPRReg destB)
488 GPRReg srcA = GPRInfo::returnValueGPR;
489 GPRReg srcB = GPRInfo::returnValueGPR2;
491 if (destA == InvalidGPRReg)
493 else if (destB == InvalidGPRReg)
495 else if (srcB != destA) {
496 // Handle the easy cases - two simple moves.
499 } else if (srcA != destB) {
500 // Handle the non-swap case - just put srcB in place first.
507 void setupResults(JSValueRegs regs)
510 move(GPRInfo::returnValueGPR, regs.gpr());
512 setupResults(regs.payloadGPR(), regs.tagGPR());
516 void jumpToExceptionHandler(VM& vm)
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);
524 void prepareForTailCallSlow(GPRReg calleeGPR = InvalidGPRReg)
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;
530 GPRReg newFramePointer = temp1;
531 GPRReg newFrameSizeGPR = temp2;
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,
536 GPRReg oldFrameSizeGPR = temp2;
538 GPRReg argCountGPR = oldFrameSizeGPR;
539 load32(Address(framePointerRegister, CallFrameSlot::argumentCount * static_cast<int>(sizeof(Register)) + PayloadOffset), argCountGPR);
542 GPRReg numParametersGPR = temp1;
544 GPRReg codeBlockGPR = numParametersGPR;
545 loadPtr(Address(framePointerRegister, CallFrameSlot::codeBlock * static_cast<int>(sizeof(Register))), codeBlockGPR);
546 load32(Address(codeBlockGPR, CodeBlock::offsetOfNumParameters()), numParametersGPR);
549 ASSERT(numParametersGPR != argCountGPR);
550 Jump argumentCountWasNotFixedUp = branch32(BelowOrEqual, numParametersGPR, argCountGPR);
551 move(numParametersGPR, argCountGPR);
552 argumentCountWasNotFixedUp.link(this);
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);
561 // The new frame pointer is at framePointer + oldFrameSize - newFrameSize
562 ASSERT(newFramePointer != oldFrameSizeGPR);
563 addPtr(framePointerRegister, oldFrameSizeGPR, newFramePointer);
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)),
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);
576 GPRReg tempGPR = temp3;
577 ASSERT(tempGPR != newFramePointer && tempGPR != newFrameSizeGPR);
579 // We don't need the current frame beyond this point. Masquerade as our
581 #if CPU(ARM) || CPU(ARM64)
582 loadPtr(Address(framePointerRegister, sizeof(void*)), linkRegister);
583 subPtr(TrustedImm32(2 * sizeof(void*)), newFrameSizeGPR);
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);
590 subPtr(TrustedImm32(sizeof(void*)), newFrameSizeGPR);
592 UNREACHABLE_FOR_PLATFORM();
594 subPtr(newFrameSizeGPR, newFramePointer);
595 loadPtr(Address(framePointerRegister), framePointerRegister);
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());
602 subPtr(TrustedImm32(sizeof(void*)), newFrameSizeGPR);
603 loadPtr(BaseIndex(stackPointerRegister, newFrameSizeGPR, TimesOne), tempGPR);
604 storePtr(tempGPR, BaseIndex(newFramePointer, newFrameSizeGPR, TimesOne));
606 branchTest32(MacroAssembler::NonZero, newFrameSizeGPR).linkTo(copyLoop, this);
609 move(newFramePointer, stackPointerRegister);
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);
622 #endif // ENABLE(JIT)