]>
git.saurik.com Git - apple/javascriptcore.git/blob - dfg/DFGCCallHelpers.h
2 * Copyright (C) 2011 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.
26 #ifndef DFGCCallHelpers_h
27 #define DFGCCallHelpers_h
29 #include <wtf/Platform.h>
33 #include "DFGAssemblyHelpers.h"
34 #include "DFGGPRInfo.h"
36 namespace JSC
{ namespace DFG
{
38 class CCallHelpers
: public AssemblyHelpers
{
40 CCallHelpers(JSGlobalData
* globalData
, CodeBlock
* codeBlock
)
41 : AssemblyHelpers(globalData
, codeBlock
)
45 // These methods used to sort arguments into the correct registers.
46 // On X86 we use cdecl calling conventions, which pass all arguments on the
47 // stack. On other architectures we may need to sort values into the
49 #if !NUMBER_OF_ARGUMENT_REGISTERS
50 unsigned m_callArgumentOffset
;
51 void resetCallArguments() { m_callArgumentOffset
= 0; }
53 // These methods are using internally to implement the callOperation methods.
54 void addCallArgument(GPRReg value
)
56 poke(value
, m_callArgumentOffset
++);
58 void addCallArgument(TrustedImm32 imm
)
60 poke(imm
, m_callArgumentOffset
++);
62 void addCallArgument(TrustedImmPtr pointer
)
64 poke(pointer
, m_callArgumentOffset
++);
66 void addCallArgument(FPRReg value
)
68 storeDouble(value
, Address(stackPointerRegister
, m_callArgumentOffset
* sizeof(void*)));
69 m_callArgumentOffset
+= sizeof(double) / sizeof(void*);
72 ALWAYS_INLINE
void setupArguments(FPRReg arg1
)
75 addCallArgument(arg1
);
78 ALWAYS_INLINE
void setupArguments(FPRReg arg1
, FPRReg arg2
)
81 addCallArgument(arg1
);
82 addCallArgument(arg2
);
85 ALWAYS_INLINE
void setupArguments(GPRReg arg1
)
88 addCallArgument(arg1
);
91 ALWAYS_INLINE
void setupArguments(GPRReg arg1
, GPRReg arg2
)
94 addCallArgument(arg1
);
95 addCallArgument(arg2
);
98 ALWAYS_INLINE
void setupArgumentsExecState()
100 resetCallArguments();
101 addCallArgument(GPRInfo::callFrameRegister
);
104 ALWAYS_INLINE
void setupArgumentsWithExecState(GPRReg arg1
)
106 resetCallArguments();
107 addCallArgument(GPRInfo::callFrameRegister
);
108 addCallArgument(arg1
);
111 ALWAYS_INLINE
void setupArgumentsWithExecState(TrustedImmPtr arg1
)
113 resetCallArguments();
114 addCallArgument(GPRInfo::callFrameRegister
);
115 addCallArgument(arg1
);
118 ALWAYS_INLINE
void setupArgumentsWithExecState(GPRReg arg1
, GPRReg arg2
)
120 resetCallArguments();
121 addCallArgument(GPRInfo::callFrameRegister
);
122 addCallArgument(arg1
);
123 addCallArgument(arg2
);
126 ALWAYS_INLINE
void setupArgumentsWithExecState(GPRReg arg1
, TrustedImmPtr arg2
)
128 resetCallArguments();
129 addCallArgument(GPRInfo::callFrameRegister
);
130 addCallArgument(arg1
);
131 addCallArgument(arg2
);
134 ALWAYS_INLINE
void setupArgumentsWithExecState(TrustedImm32 arg1
, TrustedImm32 arg2
)
136 resetCallArguments();
137 addCallArgument(GPRInfo::callFrameRegister
);
138 addCallArgument(arg1
);
139 addCallArgument(arg2
);
142 ALWAYS_INLINE
void setupArgumentsWithExecState(TrustedImmPtr arg1
, TrustedImmPtr arg2
)
144 resetCallArguments();
145 addCallArgument(GPRInfo::callFrameRegister
);
146 addCallArgument(arg1
);
147 addCallArgument(arg2
);
150 ALWAYS_INLINE
void setupArgumentsWithExecState(GPRReg arg1
, GPRReg arg2
, GPRReg arg3
)
152 resetCallArguments();
153 addCallArgument(GPRInfo::callFrameRegister
);
154 addCallArgument(arg1
);
155 addCallArgument(arg2
);
156 addCallArgument(arg3
);
159 ALWAYS_INLINE
void setupArgumentsWithExecState(GPRReg arg1
, GPRReg arg2
, TrustedImmPtr arg3
)
161 resetCallArguments();
162 addCallArgument(GPRInfo::callFrameRegister
);
163 addCallArgument(arg1
);
164 addCallArgument(arg2
);
165 addCallArgument(arg3
);
168 ALWAYS_INLINE
void setupArgumentsWithExecState(GPRReg arg1
, TrustedImm32 arg2
, TrustedImmPtr arg3
)
170 resetCallArguments();
171 addCallArgument(GPRInfo::callFrameRegister
);
172 addCallArgument(arg1
);
173 addCallArgument(arg2
);
174 addCallArgument(arg3
);
177 ALWAYS_INLINE
void setupArgumentsWithExecState(GPRReg arg1
, TrustedImmPtr arg2
, TrustedImmPtr arg3
)
179 resetCallArguments();
180 addCallArgument(GPRInfo::callFrameRegister
);
181 addCallArgument(arg1
);
182 addCallArgument(arg2
);
183 addCallArgument(arg3
);
186 ALWAYS_INLINE
void setupArgumentsWithExecState(GPRReg arg1
, GPRReg arg2
, GPRReg arg3
, GPRReg arg4
)
188 resetCallArguments();
189 addCallArgument(GPRInfo::callFrameRegister
);
190 addCallArgument(arg1
);
191 addCallArgument(arg2
);
192 addCallArgument(arg3
);
193 addCallArgument(arg4
);
196 ALWAYS_INLINE
void setupArgumentsWithExecState(GPRReg arg1
, GPRReg arg2
, GPRReg arg3
, TrustedImmPtr arg4
)
198 resetCallArguments();
199 addCallArgument(GPRInfo::callFrameRegister
);
200 addCallArgument(arg1
);
201 addCallArgument(arg2
);
202 addCallArgument(arg3
);
203 addCallArgument(arg4
);
206 ALWAYS_INLINE
void setupArgumentsWithExecState(GPRReg arg1
, GPRReg arg2
, TrustedImm32 arg3
, TrustedImm32 arg4
)
208 resetCallArguments();
209 addCallArgument(GPRInfo::callFrameRegister
);
210 addCallArgument(arg1
);
211 addCallArgument(arg2
);
212 addCallArgument(arg3
);
213 addCallArgument(arg4
);
216 ALWAYS_INLINE
void setupArgumentsWithExecState(TrustedImm32 arg1
, TrustedImm32 arg2
, GPRReg arg3
, GPRReg arg4
)
218 resetCallArguments();
219 addCallArgument(GPRInfo::callFrameRegister
);
220 addCallArgument(arg1
);
221 addCallArgument(arg2
);
222 addCallArgument(arg3
);
223 addCallArgument(arg4
);
226 ALWAYS_INLINE
void setupArgumentsWithExecState(GPRReg arg1
, GPRReg arg2
, GPRReg arg3
, GPRReg arg4
, GPRReg arg5
)
228 resetCallArguments();
229 addCallArgument(GPRInfo::callFrameRegister
);
230 addCallArgument(arg1
);
231 addCallArgument(arg2
);
232 addCallArgument(arg3
);
233 addCallArgument(arg4
);
234 addCallArgument(arg5
);
236 #endif // !NUMBER_OF_ARGUMENT_REGISTERS
237 // These methods are suitable for any calling convention that provides for
238 // at least 4 argument registers, e.g. X86_64, ARMv7.
239 #if NUMBER_OF_ARGUMENT_REGISTERS >= 4
240 template<GPRReg destA
, GPRReg destB
>
241 void setupTwoStubArgs(GPRReg srcA
, GPRReg srcB
)
243 // Assuming that srcA != srcB, there are 7 interesting states the registers may be in:
244 // (1) both are already in arg regs, the right way around.
245 // (2) both are already in arg regs, the wrong way around.
246 // (3) neither are currently in arg registers.
247 // (4) srcA in in its correct reg.
248 // (5) srcA in in the incorrect reg.
249 // (6) srcB in in its correct reg.
250 // (7) srcB in in the incorrect reg.
252 // The trivial approach is to simply emit two moves, to put srcA in place then srcB in
253 // place (the MacroAssembler will omit redundant moves). This apporach will be safe in
254 // cases 1, 3, 4, 5, 6, and in cases where srcA==srcB. The two problem cases are 2
255 // (requires a swap) and 7 (must move srcB first, to avoid trampling.)
258 // Handle the easy cases - two simple moves.
261 } else if (srcA
!= destB
) {
262 // Handle the non-swap case - just put srcB in place first.
269 template<FPRReg destA
, FPRReg destB
>
270 void setupTwoStubArgs(FPRReg srcA
, FPRReg srcB
)
272 // Assuming that srcA != srcB, there are 7 interesting states the registers may be in:
273 // (1) both are already in arg regs, the right way around.
274 // (2) both are already in arg regs, the wrong way around.
275 // (3) neither are currently in arg registers.
276 // (4) srcA in in its correct reg.
277 // (5) srcA in in the incorrect reg.
278 // (6) srcB in in its correct reg.
279 // (7) srcB in in the incorrect reg.
281 // The trivial approach is to simply emit two moves, to put srcA in place then srcB in
282 // place (the MacroAssembler will omit redundant moves). This apporach will be safe in
283 // cases 1, 3, 4, 5, 6, and in cases where srcA==srcB. The two problem cases are 2
284 // (requires a swap) and 7 (must move srcB first, to avoid trampling.)
287 // Handle the easy cases - two simple moves.
288 moveDouble(srcA
, destA
);
289 moveDouble(srcB
, destB
);
294 // Handle the non-swap case - just put srcB in place first.
295 moveDouble(srcB
, destB
);
296 moveDouble(srcA
, destA
);
300 ASSERT(srcB
== destA
&& srcA
== destB
);
301 // Need to swap; pick a temporary register.
303 if (destA
!= FPRInfo::argumentFPR3
&& destA
!= FPRInfo::argumentFPR3
)
304 temp
= FPRInfo::argumentFPR3
;
305 else if (destA
!= FPRInfo::argumentFPR2
&& destA
!= FPRInfo::argumentFPR2
)
306 temp
= FPRInfo::argumentFPR2
;
308 ASSERT(destA
!= FPRInfo::argumentFPR1
&& destA
!= FPRInfo::argumentFPR1
);
309 temp
= FPRInfo::argumentFPR1
;
311 moveDouble(destA
, temp
);
312 moveDouble(destB
, destA
);
313 moveDouble(temp
, destB
);
316 void setupStubArguments(GPRReg arg1
, GPRReg arg2
)
318 setupTwoStubArgs
<GPRInfo::argumentGPR1
, GPRInfo::argumentGPR2
>(arg1
, arg2
);
320 void setupStubArguments(GPRReg arg1
, GPRReg arg2
, GPRReg arg3
)
322 // If neither of arg2/arg3 are in our way, then we can move arg1 into place.
323 // Then we can use setupTwoStubArgs to fix arg2/arg3.
324 if (arg2
!= GPRInfo::argumentGPR1
&& arg3
!= GPRInfo::argumentGPR1
) {
325 move(arg1
, GPRInfo::argumentGPR1
);
326 setupTwoStubArgs
<GPRInfo::argumentGPR2
, GPRInfo::argumentGPR3
>(arg2
, arg3
);
330 // If neither of arg1/arg3 are in our way, then we can move arg2 into place.
331 // Then we can use setupTwoStubArgs to fix arg1/arg3.
332 if (arg1
!= GPRInfo::argumentGPR2
&& arg3
!= GPRInfo::argumentGPR2
) {
333 move(arg2
, GPRInfo::argumentGPR2
);
334 setupTwoStubArgs
<GPRInfo::argumentGPR1
, GPRInfo::argumentGPR3
>(arg1
, arg3
);
338 // If neither of arg1/arg2 are in our way, then we can move arg3 into place.
339 // Then we can use setupTwoStubArgs to fix arg1/arg2.
340 if (arg1
!= GPRInfo::argumentGPR3
&& arg2
!= GPRInfo::argumentGPR3
) {
341 move(arg3
, GPRInfo::argumentGPR3
);
342 setupTwoStubArgs
<GPRInfo::argumentGPR1
, GPRInfo::argumentGPR2
>(arg1
, arg2
);
346 // If we get here, we haven't been able to move any of arg1/arg2/arg3.
347 // Since all three are blocked, then all three must already be in the argument register.
348 // But are they in the right ones?
350 // First, ensure arg1 is in place.
351 if (arg1
!= GPRInfo::argumentGPR1
) {
352 swap(arg1
, GPRInfo::argumentGPR1
);
354 // If arg1 wasn't in argumentGPR1, one of arg2/arg3 must be.
355 ASSERT(arg2
== GPRInfo::argumentGPR1
|| arg3
== GPRInfo::argumentGPR1
);
356 // If arg2 was in argumentGPR1 it no longer is (due to the swap).
357 // Otherwise arg3 must have been. Mark him as moved.
358 if (arg2
== GPRInfo::argumentGPR1
)
364 // Either arg2 & arg3 need swapping, or we're all done.
365 ASSERT((arg2
== GPRInfo::argumentGPR2
|| arg3
== GPRInfo::argumentGPR3
)
366 || (arg2
== GPRInfo::argumentGPR3
|| arg3
== GPRInfo::argumentGPR2
));
368 if (arg2
!= GPRInfo::argumentGPR2
)
369 swap(GPRInfo::argumentGPR2
, GPRInfo::argumentGPR3
);
373 ALWAYS_INLINE
void setupArguments(FPRReg arg1
)
375 moveDouble(arg1
, FPRInfo::argumentFPR0
);
378 ALWAYS_INLINE
void setupArguments(FPRReg arg1
, FPRReg arg2
)
380 setupTwoStubArgs
<FPRInfo::argumentFPR0
, FPRInfo::argumentFPR1
>(arg1
, arg2
);
383 ALWAYS_INLINE
void setupArguments(FPRReg arg1
)
385 assembler().vmov(GPRInfo::argumentGPR0
, GPRInfo::argumentGPR1
, arg1
);
388 ALWAYS_INLINE
void setupArguments(FPRReg arg1
, FPRReg arg2
)
390 assembler().vmov(GPRInfo::argumentGPR0
, GPRInfo::argumentGPR1
, arg1
);
391 assembler().vmov(GPRInfo::argumentGPR2
, GPRInfo::argumentGPR3
, arg2
);
395 ALWAYS_INLINE
void setupArguments(GPRReg arg1
)
397 move(arg1
, GPRInfo::argumentGPR0
);
400 ALWAYS_INLINE
void setupArguments(GPRReg arg1
, GPRReg arg2
)
402 setupTwoStubArgs
<GPRInfo::argumentGPR0
, GPRInfo::argumentGPR1
>(arg1
, arg2
);
405 ALWAYS_INLINE
void setupArgumentsExecState()
407 move(GPRInfo::callFrameRegister
, GPRInfo::argumentGPR0
);
410 ALWAYS_INLINE
void setupArgumentsWithExecState(GPRReg arg1
)
412 move(arg1
, GPRInfo::argumentGPR1
);
413 move(GPRInfo::callFrameRegister
, GPRInfo::argumentGPR0
);
416 ALWAYS_INLINE
void setupArgumentsWithExecState(TrustedImmPtr arg1
)
418 move(arg1
, GPRInfo::argumentGPR1
);
419 move(GPRInfo::callFrameRegister
, GPRInfo::argumentGPR0
);
422 ALWAYS_INLINE
void setupArgumentsWithExecState(GPRReg arg1
, GPRReg arg2
)
424 setupStubArguments(arg1
, arg2
);
425 move(GPRInfo::callFrameRegister
, GPRInfo::argumentGPR0
);
428 ALWAYS_INLINE
void setupArgumentsWithExecState(GPRReg arg1
, TrustedImmPtr arg2
)
430 move(arg1
, GPRInfo::argumentGPR1
);
431 move(arg2
, GPRInfo::argumentGPR2
);
432 move(GPRInfo::callFrameRegister
, GPRInfo::argumentGPR0
);
435 ALWAYS_INLINE
void setupArgumentsWithExecState(GPRReg arg1
, ImmPtr arg2
)
437 move(arg1
, GPRInfo::argumentGPR1
);
438 move(arg2
, GPRInfo::argumentGPR2
);
439 move(GPRInfo::callFrameRegister
, GPRInfo::argumentGPR0
);
442 ALWAYS_INLINE
void setupArgumentsWithExecState(TrustedImmPtr arg1
, GPRReg arg2
)
444 move(arg2
, GPRInfo::argumentGPR2
); // Move this first, so setting arg1 does not trample!
445 move(arg1
, GPRInfo::argumentGPR1
);
446 move(GPRInfo::callFrameRegister
, GPRInfo::argumentGPR0
);
449 ALWAYS_INLINE
void setupArgumentsWithExecState(ImmPtr arg1
, GPRReg arg2
)
451 move(arg2
, GPRInfo::argumentGPR2
); // Move this first, so setting arg1 does not trample!
452 move(arg1
, GPRInfo::argumentGPR1
);
453 move(GPRInfo::callFrameRegister
, GPRInfo::argumentGPR0
);
456 ALWAYS_INLINE
void setupArgumentsWithExecState(TrustedImm32 arg1
, TrustedImm32 arg2
)
458 move(arg1
, GPRInfo::argumentGPR1
);
459 move(arg2
, GPRInfo::argumentGPR2
);
460 move(GPRInfo::callFrameRegister
, GPRInfo::argumentGPR0
);
463 ALWAYS_INLINE
void setupArgumentsWithExecState(TrustedImmPtr arg1
, TrustedImmPtr arg2
)
465 move(arg1
, GPRInfo::argumentGPR1
);
466 move(arg2
, GPRInfo::argumentGPR2
);
467 move(GPRInfo::callFrameRegister
, GPRInfo::argumentGPR0
);
470 ALWAYS_INLINE
void setupArgumentsWithExecState(GPRReg arg1
, GPRReg arg2
, GPRReg arg3
)
472 setupStubArguments(arg1
, arg2
, arg3
);
473 move(GPRInfo::callFrameRegister
, GPRInfo::argumentGPR0
);
476 ALWAYS_INLINE
void setupArgumentsWithExecState(GPRReg arg1
, GPRReg arg2
, TrustedImm32 arg3
)
478 setupStubArguments(arg1
, arg2
);
479 move(arg3
, GPRInfo::argumentGPR3
);
480 move(GPRInfo::callFrameRegister
, GPRInfo::argumentGPR0
);
483 ALWAYS_INLINE
void setupArgumentsWithExecState(GPRReg arg1
, TrustedImm32 arg2
, TrustedImmPtr arg3
)
485 move(arg1
, GPRInfo::argumentGPR1
);
486 move(arg2
, GPRInfo::argumentGPR2
);
487 move(arg3
, GPRInfo::argumentGPR3
);
488 move(GPRInfo::callFrameRegister
, GPRInfo::argumentGPR0
);
491 ALWAYS_INLINE
void setupArgumentsWithExecState(GPRReg arg1
, TrustedImmPtr arg2
, TrustedImmPtr arg3
)
493 move(arg1
, GPRInfo::argumentGPR1
);
494 move(arg2
, GPRInfo::argumentGPR2
);
495 move(arg3
, GPRInfo::argumentGPR3
);
496 move(GPRInfo::callFrameRegister
, GPRInfo::argumentGPR0
);
499 ALWAYS_INLINE
void setupArgumentsWithExecState(GPRReg arg1
, GPRReg arg2
, TrustedImmPtr arg3
)
501 setupStubArguments(arg1
, arg2
);
502 move(arg3
, GPRInfo::argumentGPR3
);
503 move(GPRInfo::callFrameRegister
, GPRInfo::argumentGPR0
);
506 ALWAYS_INLINE
void setupArgumentsWithExecState(TrustedImm32 arg1
, TrustedImm32 arg2
, GPRReg arg3
)
508 move(arg1
, GPRInfo::argumentGPR1
);
509 move(arg2
, GPRInfo::argumentGPR2
);
510 move(arg3
, GPRInfo::argumentGPR3
);
511 move(GPRInfo::callFrameRegister
, GPRInfo::argumentGPR0
);
514 #endif // NUMBER_OF_ARGUMENT_REGISTERS >= 4
515 // These methods are suitable for any calling convention that provides for
516 // exactly 4 argument registers, e.g. ARMv7.
517 #if NUMBER_OF_ARGUMENT_REGISTERS == 4
518 ALWAYS_INLINE
void setupArgumentsWithExecState(GPRReg arg1
, GPRReg arg2
, GPRReg arg3
, GPRReg arg4
)
521 setupArgumentsWithExecState(arg1
, arg2
, arg3
);
524 ALWAYS_INLINE
void setupArgumentsWithExecState(GPRReg arg1
, GPRReg arg2
, TrustedImm32 arg3
, TrustedImm32 arg4
)
527 setupArgumentsWithExecState(arg1
, arg2
, arg3
);
530 ALWAYS_INLINE
void setupArgumentsWithExecState(TrustedImm32 arg1
, TrustedImm32 arg2
, GPRReg arg3
, GPRReg arg4
)
533 setupArgumentsWithExecState(arg1
, arg2
, arg3
);
536 ALWAYS_INLINE
void setupArgumentsWithExecState(GPRReg arg1
, GPRReg arg2
, GPRReg arg3
, TrustedImmPtr arg4
)
539 setupArgumentsWithExecState(arg1
, arg2
, arg3
);
542 ALWAYS_INLINE
void setupArgumentsWithExecState(GPRReg arg1
, GPRReg arg2
, GPRReg arg3
, GPRReg arg4
, GPRReg arg5
)
546 setupArgumentsWithExecState(arg1
, arg2
, arg3
);
548 #endif // NUMBER_OF_ARGUMENT_REGISTERS == 4
550 void setupResults(GPRReg destA
, GPRReg destB
)
552 GPRReg srcA
= GPRInfo::returnValueGPR
;
553 GPRReg srcB
= GPRInfo::returnValueGPR2
;
556 // Handle the easy cases - two simple moves.
559 } else if (srcA
!= destB
) {
560 // Handle the non-swap case - just put srcB in place first.
568 } } // namespace JSC::DFG
570 #endif // ENABLE(DFG_JIT)
572 #endif // DFGCCallHelpers_h