7a11ea695ab56f4a311a2b5e703e5c733201142d
[WebKit-https.git] / Source / JavaScriptCore / jit / ThunkGenerators.cpp
1 /*
2  * Copyright (C) 2010, 2012-2014, 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. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "ThunkGenerators.h"
28
29 #include "CodeBlock.h"
30 #include "DFGSpeculativeJIT.h"
31 #include "JITOperations.h"
32 #include "JSArray.h"
33 #include "JSBoundFunction.h"
34 #include "MathCommon.h"
35 #include "MaxFrameExtentForSlowPathCall.h"
36 #include "JSCInlines.h"
37 #include "SpecializedThunkJIT.h"
38 #include <wtf/InlineASM.h>
39 #include <wtf/StringPrintStream.h>
40 #include <wtf/text/StringImpl.h>
41
42 #if ENABLE(JIT)
43
44 namespace JSC {
45
46 inline void emitPointerValidation(CCallHelpers& jit, GPRReg pointerGPR)
47 {
48     if (ASSERT_DISABLED)
49         return;
50     CCallHelpers::Jump isNonZero = jit.branchTestPtr(CCallHelpers::NonZero, pointerGPR);
51     jit.abortWithReason(TGInvalidPointer);
52     isNonZero.link(&jit);
53     jit.pushToSave(pointerGPR);
54     jit.load8(pointerGPR, pointerGPR);
55     jit.popToRestore(pointerGPR);
56 }
57
58 // We will jump here if the JIT code tries to make a call, but the
59 // linking helper (C++ code) decides to throw an exception instead.
60 MacroAssemblerCodeRef throwExceptionFromCallSlowPathGenerator(VM* vm)
61 {
62     CCallHelpers jit(vm);
63     
64     // The call pushed a return address, so we need to pop it back off to re-align the stack,
65     // even though we won't use it.
66     jit.preserveReturnAddressAfterCall(GPRInfo::nonPreservedNonReturnGPR);
67
68     jit.copyCalleeSavesToVMEntryFrameCalleeSavesBuffer();
69
70     jit.setupArguments(CCallHelpers::TrustedImmPtr(vm), GPRInfo::callFrameRegister);
71     jit.move(CCallHelpers::TrustedImmPtr(bitwise_cast<void*>(lookupExceptionHandler)), GPRInfo::nonArgGPR0);
72     emitPointerValidation(jit, GPRInfo::nonArgGPR0);
73     jit.call(GPRInfo::nonArgGPR0);
74     jit.jumpToExceptionHandler();
75
76     LinkBuffer patchBuffer(*vm, jit, GLOBAL_THUNK_ID);
77     return FINALIZE_CODE(patchBuffer, ("Throw exception from call slow path thunk"));
78 }
79
80 static void slowPathFor(
81     CCallHelpers& jit, VM* vm, Sprt_JITOperation_ECli slowPathFunction)
82 {
83     jit.emitFunctionPrologue();
84     jit.storePtr(GPRInfo::callFrameRegister, &vm->topCallFrame);
85 #if OS(WINDOWS) && CPU(X86_64)
86     // Windows X86_64 needs some space pointed to by arg0 for return types larger than 64 bits.
87     // Other argument values are shift by 1. Use space on the stack for our two return values.
88     // Moving the stack down maxFrameExtentForSlowPathCall bytes gives us room for our 3 arguments
89     // and space for the 16 byte return area.
90     jit.addPtr(CCallHelpers::TrustedImm32(-maxFrameExtentForSlowPathCall), CCallHelpers::stackPointerRegister);
91     jit.move(GPRInfo::regT2, GPRInfo::argumentGPR2);
92     jit.addPtr(CCallHelpers::TrustedImm32(32), CCallHelpers::stackPointerRegister, GPRInfo::argumentGPR0);
93     jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR1);
94     jit.move(CCallHelpers::TrustedImmPtr(bitwise_cast<void*>(slowPathFunction)), GPRInfo::nonArgGPR0);
95     emitPointerValidation(jit, GPRInfo::nonArgGPR0);
96     jit.call(GPRInfo::nonArgGPR0);
97     jit.loadPtr(CCallHelpers::Address(GPRInfo::returnValueGPR, 8), GPRInfo::returnValueGPR2);
98     jit.loadPtr(CCallHelpers::Address(GPRInfo::returnValueGPR), GPRInfo::returnValueGPR);
99     jit.addPtr(CCallHelpers::TrustedImm32(maxFrameExtentForSlowPathCall), CCallHelpers::stackPointerRegister);
100 #else
101     if (maxFrameExtentForSlowPathCall)
102         jit.addPtr(CCallHelpers::TrustedImm32(-maxFrameExtentForSlowPathCall), CCallHelpers::stackPointerRegister);
103     jit.setupArgumentsWithExecState(GPRInfo::regT2);
104     jit.move(CCallHelpers::TrustedImmPtr(bitwise_cast<void*>(slowPathFunction)), GPRInfo::nonArgGPR0);
105     emitPointerValidation(jit, GPRInfo::nonArgGPR0);
106     jit.call(GPRInfo::nonArgGPR0);
107     if (maxFrameExtentForSlowPathCall)
108         jit.addPtr(CCallHelpers::TrustedImm32(maxFrameExtentForSlowPathCall), CCallHelpers::stackPointerRegister);
109 #endif
110
111     // This slow call will return the address of one of the following:
112     // 1) Exception throwing thunk.
113     // 2) Host call return value returner thingy.
114     // 3) The function to call.
115     // The second return value GPR will hold a non-zero value for tail calls.
116
117     emitPointerValidation(jit, GPRInfo::returnValueGPR);
118     jit.emitFunctionEpilogue();
119
120     RELEASE_ASSERT(reinterpret_cast<void*>(KeepTheFrame) == reinterpret_cast<void*>(0));
121     CCallHelpers::Jump doNotTrash = jit.branchTestPtr(CCallHelpers::Zero, GPRInfo::returnValueGPR2);
122
123     jit.preserveReturnAddressAfterCall(GPRInfo::nonPreservedNonReturnGPR);
124     jit.prepareForTailCallSlow(GPRInfo::returnValueGPR);
125
126     doNotTrash.link(&jit);
127     jit.jump(GPRInfo::returnValueGPR);
128 }
129
130 MacroAssemblerCodeRef linkCallThunkGenerator(VM* vm)
131 {
132     // The return address is on the stack or in the link register. We will hence
133     // save the return address to the call frame while we make a C++ function call
134     // to perform linking and lazy compilation if necessary. We expect the callee
135     // to be in regT0/regT1 (payload/tag), the CallFrame to have already
136     // been adjusted, and all other registers to be available for use.
137     CCallHelpers jit(vm);
138     
139     slowPathFor(jit, vm, operationLinkCall);
140     
141     LinkBuffer patchBuffer(*vm, jit, GLOBAL_THUNK_ID);
142     return FINALIZE_CODE(patchBuffer, ("Link call slow path thunk"));
143 }
144
145 // For closure optimizations, we only include calls, since if you're using closures for
146 // object construction then you're going to lose big time anyway.
147 MacroAssemblerCodeRef linkPolymorphicCallThunkGenerator(VM* vm)
148 {
149     CCallHelpers jit(vm);
150     
151     slowPathFor(jit, vm, operationLinkPolymorphicCall);
152     
153     LinkBuffer patchBuffer(*vm, jit, GLOBAL_THUNK_ID);
154     return FINALIZE_CODE(patchBuffer, ("Link polymorphic call slow path thunk"));
155 }
156
157 // FIXME: We should distinguish between a megamorphic virtual call vs. a slow
158 // path virtual call so that we can enable fast tail calls for megamorphic
159 // virtual calls by using the shuffler.
160 // https://bugs.webkit.org/show_bug.cgi?id=148831
161 MacroAssemblerCodeRef virtualThunkFor(VM* vm, CallLinkInfo& callLinkInfo)
162 {
163     // The callee is in regT0 (for JSVALUE32_64, the tag is in regT1).
164     // The return address is on the stack, or in the link register. We will hence
165     // jump to the callee, or save the return address to the call frame while we
166     // make a C++ function call to the appropriate JIT operation.
167
168     CCallHelpers jit(vm);
169     
170     CCallHelpers::JumpList slowCase;
171     
172     // This is a slow path execution, and regT2 contains the CallLinkInfo. Count the
173     // slow path execution for the profiler.
174     jit.add32(
175         CCallHelpers::TrustedImm32(1),
176         CCallHelpers::Address(GPRInfo::regT2, CallLinkInfo::offsetOfSlowPathCount()));
177
178     // FIXME: we should have a story for eliminating these checks. In many cases,
179     // the DFG knows that the value is definitely a cell, or definitely a function.
180     
181 #if USE(JSVALUE64)
182     slowCase.append(
183         jit.branchTest64(
184             CCallHelpers::NonZero, GPRInfo::regT0, GPRInfo::tagMaskRegister));
185 #else
186     slowCase.append(
187         jit.branch32(
188             CCallHelpers::NotEqual, GPRInfo::regT1,
189             CCallHelpers::TrustedImm32(JSValue::CellTag)));
190 #endif
191     slowCase.append(jit.branchIfNotType(GPRInfo::regT0, JSFunctionType));
192     
193     // Now we know we have a JSFunction.
194     
195     jit.loadPtr(
196         CCallHelpers::Address(GPRInfo::regT0, JSFunction::offsetOfExecutable()),
197         GPRInfo::regT4);
198     jit.loadPtr(
199         CCallHelpers::Address(
200             GPRInfo::regT4, ExecutableBase::offsetOfJITCodeWithArityCheckFor(
201                 callLinkInfo.specializationKind())),
202         GPRInfo::regT4);
203     slowCase.append(jit.branchTestPtr(CCallHelpers::Zero, GPRInfo::regT4));
204     
205     // Now we know that we have a CodeBlock, and we're committed to making a fast
206     // call.
207     
208     // Make a tail call. This will return back to JIT code.
209     emitPointerValidation(jit, GPRInfo::regT4);
210     if (callLinkInfo.isTailCall()) {
211         jit.preserveReturnAddressAfterCall(GPRInfo::regT0);
212         jit.prepareForTailCallSlow(GPRInfo::regT4);
213     }
214     jit.jump(GPRInfo::regT4);
215
216     slowCase.link(&jit);
217     
218     // Here we don't know anything, so revert to the full slow path.
219     
220     slowPathFor(jit, vm, operationVirtualCall);
221     
222     LinkBuffer patchBuffer(*vm, jit, GLOBAL_THUNK_ID);
223     return FINALIZE_CODE(
224         patchBuffer,
225         ("Virtual %s slow path thunk",
226         callLinkInfo.callMode() == CallMode::Regular ? "call" : callLinkInfo.callMode() == CallMode::Tail ? "tail call" : "construct"));
227 }
228
229 enum ThunkEntryType { EnterViaCall, EnterViaJumpWithSavedTags, EnterViaJumpWithoutSavedTags };
230
231 static MacroAssemblerCodeRef nativeForGenerator(VM* vm, CodeSpecializationKind kind, ThunkEntryType entryType = EnterViaCall)
232 {
233     // FIXME: This should be able to log ShadowChicken prologue packets.
234     // https://bugs.webkit.org/show_bug.cgi?id=155689
235     
236     int executableOffsetToFunction = NativeExecutable::offsetOfNativeFunctionFor(kind);
237     
238     JSInterfaceJIT jit(vm);
239
240     switch (entryType) {
241     case EnterViaCall:
242         jit.emitFunctionPrologue();
243         break;
244     case EnterViaJumpWithSavedTags:
245 #if USE(JSVALUE64)
246         // We're coming from a specialized thunk that has saved the prior tag registers' contents.
247         // Restore them now.
248 #if CPU(ARM64)
249         jit.popPair(JSInterfaceJIT::tagTypeNumberRegister, JSInterfaceJIT::tagMaskRegister);
250 #else
251         jit.pop(JSInterfaceJIT::tagMaskRegister);
252         jit.pop(JSInterfaceJIT::tagTypeNumberRegister);
253 #endif
254 #endif
255         break;
256     case EnterViaJumpWithoutSavedTags:
257         jit.move(JSInterfaceJIT::framePointerRegister, JSInterfaceJIT::stackPointerRegister);
258         break;
259     }
260
261     jit.emitPutToCallFrameHeader(0, CallFrameSlot::codeBlock);
262     jit.storePtr(JSInterfaceJIT::callFrameRegister, &vm->topCallFrame);
263
264 #if CPU(X86)
265     // Calling convention:      f(ecx, edx, ...);
266     // Host function signature: f(ExecState*);
267     jit.move(JSInterfaceJIT::callFrameRegister, X86Registers::ecx);
268
269     jit.subPtr(JSInterfaceJIT::TrustedImm32(8), JSInterfaceJIT::stackPointerRegister); // Align stack after prologue.
270
271     // call the function
272     jit.emitGetFromCallFrameHeaderPtr(CallFrameSlot::callee, JSInterfaceJIT::regT1);
273     jit.loadPtr(JSInterfaceJIT::Address(JSInterfaceJIT::regT1, JSFunction::offsetOfExecutable()), JSInterfaceJIT::regT1);
274     jit.call(JSInterfaceJIT::Address(JSInterfaceJIT::regT1, executableOffsetToFunction));
275
276     jit.addPtr(JSInterfaceJIT::TrustedImm32(8), JSInterfaceJIT::stackPointerRegister);
277
278 #elif CPU(X86_64)
279 #if !OS(WINDOWS)
280     // Calling convention:      f(edi, esi, edx, ecx, ...);
281     // Host function signature: f(ExecState*);
282     jit.move(JSInterfaceJIT::callFrameRegister, X86Registers::edi);
283
284     jit.emitGetFromCallFrameHeaderPtr(CallFrameSlot::callee, X86Registers::esi);
285     jit.loadPtr(JSInterfaceJIT::Address(X86Registers::esi, JSFunction::offsetOfExecutable()), X86Registers::r9);
286     jit.call(JSInterfaceJIT::Address(X86Registers::r9, executableOffsetToFunction));
287
288 #else
289     // Calling convention:      f(ecx, edx, r8, r9, ...);
290     // Host function signature: f(ExecState*);
291     jit.move(JSInterfaceJIT::callFrameRegister, X86Registers::ecx);
292
293     // Leave space for the callee parameter home addresses.
294     // At this point the stack is aligned to 16 bytes, but if this changes at some point, we need to emit code to align it.
295     jit.subPtr(JSInterfaceJIT::TrustedImm32(4 * sizeof(int64_t)), JSInterfaceJIT::stackPointerRegister);
296
297     jit.emitGetFromCallFrameHeaderPtr(CallFrameSlot::callee, X86Registers::edx);
298     jit.loadPtr(JSInterfaceJIT::Address(X86Registers::edx, JSFunction::offsetOfExecutable()), X86Registers::r9);
299     jit.call(JSInterfaceJIT::Address(X86Registers::r9, executableOffsetToFunction));
300
301     jit.addPtr(JSInterfaceJIT::TrustedImm32(4 * sizeof(int64_t)), JSInterfaceJIT::stackPointerRegister);
302 #endif
303
304 #elif CPU(ARM64)
305     COMPILE_ASSERT(ARM64Registers::x0 != JSInterfaceJIT::regT3, T3_not_trampled_by_arg_0);
306     COMPILE_ASSERT(ARM64Registers::x1 != JSInterfaceJIT::regT3, T3_not_trampled_by_arg_1);
307     COMPILE_ASSERT(ARM64Registers::x2 != JSInterfaceJIT::regT3, T3_not_trampled_by_arg_2);
308
309     // Host function signature: f(ExecState*);
310     jit.move(JSInterfaceJIT::callFrameRegister, ARM64Registers::x0);
311
312     jit.emitGetFromCallFrameHeaderPtr(CallFrameSlot::callee, ARM64Registers::x1);
313     jit.loadPtr(JSInterfaceJIT::Address(ARM64Registers::x1, JSFunction::offsetOfExecutable()), ARM64Registers::x2);
314     jit.call(JSInterfaceJIT::Address(ARM64Registers::x2, executableOffsetToFunction));
315 #elif CPU(ARM) || CPU(SH4) || CPU(MIPS)
316 #if CPU(MIPS)
317     // Allocate stack space for (unused) 16 bytes (8-byte aligned) for 4 arguments.
318     jit.subPtr(JSInterfaceJIT::TrustedImm32(16), JSInterfaceJIT::stackPointerRegister);
319 #endif
320
321     // Calling convention is f(argumentGPR0, argumentGPR1, ...).
322     // Host function signature is f(ExecState*).
323     jit.move(JSInterfaceJIT::callFrameRegister, JSInterfaceJIT::argumentGPR0);
324
325     jit.emitGetFromCallFrameHeaderPtr(CallFrameSlot::callee, JSInterfaceJIT::argumentGPR1);
326     jit.loadPtr(JSInterfaceJIT::Address(JSInterfaceJIT::argumentGPR1, JSFunction::offsetOfExecutable()), JSInterfaceJIT::regT2);
327     jit.call(JSInterfaceJIT::Address(JSInterfaceJIT::regT2, executableOffsetToFunction));
328
329 #if CPU(MIPS)
330     // Restore stack space
331     jit.addPtr(JSInterfaceJIT::TrustedImm32(16), JSInterfaceJIT::stackPointerRegister);
332 #endif
333 #else
334 #error "JIT not supported on this platform."
335     UNUSED_PARAM(executableOffsetToFunction);
336     abortWithReason(TGNotSupported);
337 #endif
338
339     // Check for an exception
340 #if USE(JSVALUE64)
341     jit.load64(vm->addressOfException(), JSInterfaceJIT::regT2);
342     JSInterfaceJIT::Jump exceptionHandler = jit.branchTest64(JSInterfaceJIT::NonZero, JSInterfaceJIT::regT2);
343 #else
344     JSInterfaceJIT::Jump exceptionHandler = jit.branch32(
345         JSInterfaceJIT::NotEqual,
346         JSInterfaceJIT::AbsoluteAddress(vm->addressOfException()),
347         JSInterfaceJIT::TrustedImm32(0));
348 #endif
349
350     jit.emitFunctionEpilogue();
351     // Return.
352     jit.ret();
353
354     // Handle an exception
355     exceptionHandler.link(&jit);
356
357     jit.copyCalleeSavesToVMEntryFrameCalleeSavesBuffer();
358     jit.storePtr(JSInterfaceJIT::callFrameRegister, &vm->topCallFrame);
359
360 #if CPU(X86) && USE(JSVALUE32_64)
361     jit.addPtr(JSInterfaceJIT::TrustedImm32(-12), JSInterfaceJIT::stackPointerRegister);
362     jit.move(JSInterfaceJIT::callFrameRegister, JSInterfaceJIT::regT0);
363     jit.push(JSInterfaceJIT::regT0);
364 #else
365 #if OS(WINDOWS)
366     // Allocate space on stack for the 4 parameter registers.
367     jit.subPtr(JSInterfaceJIT::TrustedImm32(4 * sizeof(int64_t)), JSInterfaceJIT::stackPointerRegister);
368 #endif
369     jit.move(JSInterfaceJIT::callFrameRegister, JSInterfaceJIT::argumentGPR0);
370 #endif
371     jit.move(JSInterfaceJIT::TrustedImmPtr(FunctionPtr(operationVMHandleException).value()), JSInterfaceJIT::regT3);
372     jit.call(JSInterfaceJIT::regT3);
373 #if CPU(X86) && USE(JSVALUE32_64)
374     jit.addPtr(JSInterfaceJIT::TrustedImm32(16), JSInterfaceJIT::stackPointerRegister);
375 #elif OS(WINDOWS)
376     jit.addPtr(JSInterfaceJIT::TrustedImm32(4 * sizeof(int64_t)), JSInterfaceJIT::stackPointerRegister);
377 #endif
378
379     jit.jumpToExceptionHandler();
380
381     LinkBuffer patchBuffer(*vm, jit, GLOBAL_THUNK_ID);
382     return FINALIZE_CODE(patchBuffer, ("native %s%s trampoline", entryType == EnterViaJumpWithSavedTags ? "Tail With Saved Tags " : entryType == EnterViaJumpWithoutSavedTags ? "Tail Without Saved Tags " : "", toCString(kind).data()));
383 }
384
385 MacroAssemblerCodeRef nativeCallGenerator(VM* vm)
386 {
387     return nativeForGenerator(vm, CodeForCall);
388 }
389
390 MacroAssemblerCodeRef nativeTailCallGenerator(VM* vm)
391 {
392     return nativeForGenerator(vm, CodeForCall, EnterViaJumpWithSavedTags);
393 }
394
395 MacroAssemblerCodeRef nativeTailCallWithoutSavedTagsGenerator(VM* vm)
396 {
397     return nativeForGenerator(vm, CodeForCall, EnterViaJumpWithoutSavedTags);
398 }
399
400 MacroAssemblerCodeRef nativeConstructGenerator(VM* vm)
401 {
402     return nativeForGenerator(vm, CodeForConstruct);
403 }
404
405 MacroAssemblerCodeRef arityFixupGenerator(VM* vm)
406 {
407     JSInterfaceJIT jit(vm);
408
409     // We enter with fixup count in argumentGPR0
410     // We have the guarantee that a0, a1, a2, t3, t4 and t5 (or t0 for Windows) are all distinct :-)
411 #if USE(JSVALUE64)
412 #if OS(WINDOWS)
413     const GPRReg extraTemp = JSInterfaceJIT::regT0;
414 #else
415     const GPRReg extraTemp = JSInterfaceJIT::regT5;
416 #endif
417 #  if CPU(X86_64)
418     jit.pop(JSInterfaceJIT::regT4);
419 #  endif
420     jit.move(JSInterfaceJIT::callFrameRegister, JSInterfaceJIT::regT3);
421     jit.load32(JSInterfaceJIT::Address(JSInterfaceJIT::callFrameRegister, CallFrameSlot::argumentCount * sizeof(Register)), JSInterfaceJIT::argumentGPR2);
422     jit.add32(JSInterfaceJIT::TrustedImm32(CallFrame::headerSizeInRegisters), JSInterfaceJIT::argumentGPR2);
423
424     // Check to see if we have extra slots we can use
425     jit.move(JSInterfaceJIT::argumentGPR0, JSInterfaceJIT::argumentGPR1);
426     jit.and32(JSInterfaceJIT::TrustedImm32(stackAlignmentRegisters() - 1), JSInterfaceJIT::argumentGPR1);
427     JSInterfaceJIT::Jump noExtraSlot = jit.branchTest32(MacroAssembler::Zero, JSInterfaceJIT::argumentGPR1);
428     jit.move(JSInterfaceJIT::TrustedImm64(ValueUndefined), extraTemp);
429     JSInterfaceJIT::Label fillExtraSlots(jit.label());
430     jit.store64(extraTemp, MacroAssembler::BaseIndex(JSInterfaceJIT::callFrameRegister, JSInterfaceJIT::argumentGPR2, JSInterfaceJIT::TimesEight));
431     jit.add32(JSInterfaceJIT::TrustedImm32(1), JSInterfaceJIT::argumentGPR2);
432     jit.branchSub32(JSInterfaceJIT::NonZero, JSInterfaceJIT::TrustedImm32(1), JSInterfaceJIT::argumentGPR1).linkTo(fillExtraSlots, &jit);
433     jit.and32(JSInterfaceJIT::TrustedImm32(-stackAlignmentRegisters()), JSInterfaceJIT::argumentGPR0);
434     JSInterfaceJIT::Jump done = jit.branchTest32(MacroAssembler::Zero, JSInterfaceJIT::argumentGPR0);
435     noExtraSlot.link(&jit);
436
437     jit.neg64(JSInterfaceJIT::argumentGPR0);
438
439     // Move current frame down argumentGPR0 number of slots
440     JSInterfaceJIT::Label copyLoop(jit.label());
441     jit.load64(JSInterfaceJIT::regT3, extraTemp);
442     jit.store64(extraTemp, MacroAssembler::BaseIndex(JSInterfaceJIT::regT3, JSInterfaceJIT::argumentGPR0, JSInterfaceJIT::TimesEight));
443     jit.addPtr(JSInterfaceJIT::TrustedImm32(8), JSInterfaceJIT::regT3);
444     jit.branchSub32(MacroAssembler::NonZero, JSInterfaceJIT::TrustedImm32(1), JSInterfaceJIT::argumentGPR2).linkTo(copyLoop, &jit);
445
446     // Fill in argumentGPR0 missing arg slots with undefined
447     jit.move(JSInterfaceJIT::argumentGPR0, JSInterfaceJIT::argumentGPR2);
448     jit.move(JSInterfaceJIT::TrustedImm64(ValueUndefined), extraTemp);
449     JSInterfaceJIT::Label fillUndefinedLoop(jit.label());
450     jit.store64(extraTemp, MacroAssembler::BaseIndex(JSInterfaceJIT::regT3, JSInterfaceJIT::argumentGPR0, JSInterfaceJIT::TimesEight));
451     jit.addPtr(JSInterfaceJIT::TrustedImm32(8), JSInterfaceJIT::regT3);
452     jit.branchAdd32(MacroAssembler::NonZero, JSInterfaceJIT::TrustedImm32(1), JSInterfaceJIT::argumentGPR2).linkTo(fillUndefinedLoop, &jit);
453     
454     // Adjust call frame register and stack pointer to account for missing args
455     jit.move(JSInterfaceJIT::argumentGPR0, extraTemp);
456     jit.lshift64(JSInterfaceJIT::TrustedImm32(3), extraTemp);
457     jit.addPtr(extraTemp, JSInterfaceJIT::callFrameRegister);
458     jit.addPtr(extraTemp, JSInterfaceJIT::stackPointerRegister);
459
460     done.link(&jit);
461
462 #  if CPU(X86_64)
463     jit.push(JSInterfaceJIT::regT4);
464 #  endif
465     jit.ret();
466 #else
467 #  if CPU(X86)
468     jit.pop(JSInterfaceJIT::regT4);
469 #  endif
470     jit.move(JSInterfaceJIT::callFrameRegister, JSInterfaceJIT::regT3);
471     jit.load32(JSInterfaceJIT::Address(JSInterfaceJIT::callFrameRegister, CallFrameSlot::argumentCount * sizeof(Register)), JSInterfaceJIT::argumentGPR2);
472     jit.add32(JSInterfaceJIT::TrustedImm32(CallFrame::headerSizeInRegisters), JSInterfaceJIT::argumentGPR2);
473
474     // Check to see if we have extra slots we can use
475     jit.move(JSInterfaceJIT::argumentGPR0, JSInterfaceJIT::argumentGPR1);
476     jit.and32(JSInterfaceJIT::TrustedImm32(stackAlignmentRegisters() - 1), JSInterfaceJIT::argumentGPR1);
477     JSInterfaceJIT::Jump noExtraSlot = jit.branchTest32(MacroAssembler::Zero, JSInterfaceJIT::argumentGPR1);
478     JSInterfaceJIT::Label fillExtraSlots(jit.label());
479     jit.move(JSInterfaceJIT::TrustedImm32(0), JSInterfaceJIT::regT5);
480     jit.store32(JSInterfaceJIT::regT5, MacroAssembler::BaseIndex(JSInterfaceJIT::callFrameRegister, JSInterfaceJIT::argumentGPR2, JSInterfaceJIT::TimesEight, PayloadOffset));
481     jit.move(JSInterfaceJIT::TrustedImm32(JSValue::UndefinedTag), JSInterfaceJIT::regT5);
482     jit.store32(JSInterfaceJIT::regT5, MacroAssembler::BaseIndex(JSInterfaceJIT::callFrameRegister, JSInterfaceJIT::argumentGPR2, JSInterfaceJIT::TimesEight, TagOffset));
483     jit.add32(JSInterfaceJIT::TrustedImm32(1), JSInterfaceJIT::argumentGPR2);
484     jit.branchSub32(JSInterfaceJIT::NonZero, JSInterfaceJIT::TrustedImm32(1), JSInterfaceJIT::argumentGPR1).linkTo(fillExtraSlots, &jit);
485     jit.and32(JSInterfaceJIT::TrustedImm32(-stackAlignmentRegisters()), JSInterfaceJIT::argumentGPR0);
486     JSInterfaceJIT::Jump done = jit.branchTest32(MacroAssembler::Zero, JSInterfaceJIT::argumentGPR0);
487     noExtraSlot.link(&jit);
488
489     jit.neg32(JSInterfaceJIT::argumentGPR0);
490
491     // Move current frame down argumentGPR0 number of slots
492     JSInterfaceJIT::Label copyLoop(jit.label());
493     jit.load32(MacroAssembler::Address(JSInterfaceJIT::regT3, PayloadOffset), JSInterfaceJIT::regT5);
494     jit.store32(JSInterfaceJIT::regT5, MacroAssembler::BaseIndex(JSInterfaceJIT::regT3, JSInterfaceJIT::argumentGPR0, JSInterfaceJIT::TimesEight, PayloadOffset));
495     jit.load32(MacroAssembler::Address(JSInterfaceJIT::regT3, TagOffset), JSInterfaceJIT::regT5);
496     jit.store32(JSInterfaceJIT::regT5, MacroAssembler::BaseIndex(JSInterfaceJIT::regT3, JSInterfaceJIT::argumentGPR0, JSInterfaceJIT::TimesEight, TagOffset));
497     jit.addPtr(JSInterfaceJIT::TrustedImm32(8), JSInterfaceJIT::regT3);
498     jit.branchSub32(MacroAssembler::NonZero, JSInterfaceJIT::TrustedImm32(1), JSInterfaceJIT::argumentGPR2).linkTo(copyLoop, &jit);
499
500     // Fill in argumentGPR0 missing arg slots with undefined
501     jit.move(JSInterfaceJIT::argumentGPR0, JSInterfaceJIT::argumentGPR2);
502     JSInterfaceJIT::Label fillUndefinedLoop(jit.label());
503     jit.move(JSInterfaceJIT::TrustedImm32(0), JSInterfaceJIT::regT5);
504     jit.store32(JSInterfaceJIT::regT5, MacroAssembler::BaseIndex(JSInterfaceJIT::regT3, JSInterfaceJIT::argumentGPR0, JSInterfaceJIT::TimesEight, PayloadOffset));
505     jit.move(JSInterfaceJIT::TrustedImm32(JSValue::UndefinedTag), JSInterfaceJIT::regT5);
506     jit.store32(JSInterfaceJIT::regT5, MacroAssembler::BaseIndex(JSInterfaceJIT::regT3, JSInterfaceJIT::argumentGPR0, JSInterfaceJIT::TimesEight, TagOffset));
507
508     jit.addPtr(JSInterfaceJIT::TrustedImm32(8), JSInterfaceJIT::regT3);
509     jit.branchAdd32(MacroAssembler::NonZero, JSInterfaceJIT::TrustedImm32(1), JSInterfaceJIT::argumentGPR2).linkTo(fillUndefinedLoop, &jit);
510
511     // Adjust call frame register and stack pointer to account for missing args
512     jit.move(JSInterfaceJIT::argumentGPR0, JSInterfaceJIT::regT5);
513     jit.lshift32(JSInterfaceJIT::TrustedImm32(3), JSInterfaceJIT::regT5);
514     jit.addPtr(JSInterfaceJIT::regT5, JSInterfaceJIT::callFrameRegister);
515     jit.addPtr(JSInterfaceJIT::regT5, JSInterfaceJIT::stackPointerRegister);
516
517     done.link(&jit);
518
519 #  if CPU(X86)
520     jit.push(JSInterfaceJIT::regT4);
521 #  endif
522     jit.ret();
523 #endif
524
525     LinkBuffer patchBuffer(*vm, jit, GLOBAL_THUNK_ID);
526     return FINALIZE_CODE(patchBuffer, ("fixup arity"));
527 }
528
529 MacroAssemblerCodeRef unreachableGenerator(VM* vm)
530 {
531     JSInterfaceJIT jit(vm);
532
533     jit.breakpoint();
534
535     LinkBuffer patchBuffer(*vm, jit, GLOBAL_THUNK_ID);
536     return FINALIZE_CODE(patchBuffer, ("unreachable thunk"));
537 }
538
539 static void stringCharLoad(SpecializedThunkJIT& jit, VM* vm)
540 {
541     // load string
542     jit.loadJSStringArgument(*vm, SpecializedThunkJIT::ThisArgument, SpecializedThunkJIT::regT0);
543
544     // Load string length to regT2, and start the process of loading the data pointer into regT0
545     jit.load32(MacroAssembler::Address(SpecializedThunkJIT::regT0, ThunkHelpers::jsStringLengthOffset()), SpecializedThunkJIT::regT2);
546     jit.loadPtr(MacroAssembler::Address(SpecializedThunkJIT::regT0, ThunkHelpers::jsStringValueOffset()), SpecializedThunkJIT::regT0);
547     jit.appendFailure(jit.branchTest32(MacroAssembler::Zero, SpecializedThunkJIT::regT0));
548
549     // load index
550     jit.loadInt32Argument(0, SpecializedThunkJIT::regT1); // regT1 contains the index
551
552     // Do an unsigned compare to simultaneously filter negative indices as well as indices that are too large
553     jit.appendFailure(jit.branch32(MacroAssembler::AboveOrEqual, SpecializedThunkJIT::regT1, SpecializedThunkJIT::regT2));
554
555     // Load the character
556     SpecializedThunkJIT::JumpList is16Bit;
557     SpecializedThunkJIT::JumpList cont8Bit;
558     // Load the string flags
559     jit.loadPtr(MacroAssembler::Address(SpecializedThunkJIT::regT0, StringImpl::flagsOffset()), SpecializedThunkJIT::regT2);
560     jit.loadPtr(MacroAssembler::Address(SpecializedThunkJIT::regT0, StringImpl::dataOffset()), SpecializedThunkJIT::regT0);
561     is16Bit.append(jit.branchTest32(MacroAssembler::Zero, SpecializedThunkJIT::regT2, MacroAssembler::TrustedImm32(StringImpl::flagIs8Bit())));
562     jit.load8(MacroAssembler::BaseIndex(SpecializedThunkJIT::regT0, SpecializedThunkJIT::regT1, MacroAssembler::TimesOne, 0), SpecializedThunkJIT::regT0);
563     cont8Bit.append(jit.jump());
564     is16Bit.link(&jit);
565     jit.load16(MacroAssembler::BaseIndex(SpecializedThunkJIT::regT0, SpecializedThunkJIT::regT1, MacroAssembler::TimesTwo, 0), SpecializedThunkJIT::regT0);
566     cont8Bit.link(&jit);
567 }
568
569 static void charToString(SpecializedThunkJIT& jit, VM* vm, MacroAssembler::RegisterID src, MacroAssembler::RegisterID dst, MacroAssembler::RegisterID scratch)
570 {
571     jit.appendFailure(jit.branch32(MacroAssembler::AboveOrEqual, src, MacroAssembler::TrustedImm32(0x100)));
572     jit.move(MacroAssembler::TrustedImmPtr(vm->smallStrings.singleCharacterStrings()), scratch);
573     jit.loadPtr(MacroAssembler::BaseIndex(scratch, src, MacroAssembler::ScalePtr, 0), dst);
574     jit.appendFailure(jit.branchTestPtr(MacroAssembler::Zero, dst));
575 }
576
577 MacroAssemblerCodeRef charCodeAtThunkGenerator(VM* vm)
578 {
579     SpecializedThunkJIT jit(vm, 1);
580     stringCharLoad(jit, vm);
581     jit.returnInt32(SpecializedThunkJIT::regT0);
582     return jit.finalize(vm->jitStubs->ctiNativeTailCall(vm), "charCodeAt");
583 }
584
585 MacroAssemblerCodeRef charAtThunkGenerator(VM* vm)
586 {
587     SpecializedThunkJIT jit(vm, 1);
588     stringCharLoad(jit, vm);
589     charToString(jit, vm, SpecializedThunkJIT::regT0, SpecializedThunkJIT::regT0, SpecializedThunkJIT::regT1);
590     jit.returnJSCell(SpecializedThunkJIT::regT0);
591     return jit.finalize(vm->jitStubs->ctiNativeTailCall(vm), "charAt");
592 }
593
594 MacroAssemblerCodeRef fromCharCodeThunkGenerator(VM* vm)
595 {
596     SpecializedThunkJIT jit(vm, 1);
597     // load char code
598     jit.loadInt32Argument(0, SpecializedThunkJIT::regT0);
599     charToString(jit, vm, SpecializedThunkJIT::regT0, SpecializedThunkJIT::regT0, SpecializedThunkJIT::regT1);
600     jit.returnJSCell(SpecializedThunkJIT::regT0);
601     return jit.finalize(vm->jitStubs->ctiNativeTailCall(vm), "fromCharCode");
602 }
603
604 MacroAssemblerCodeRef clz32ThunkGenerator(VM* vm)
605 {
606     SpecializedThunkJIT jit(vm, 1);
607     MacroAssembler::Jump nonIntArgJump;
608     jit.loadInt32Argument(0, SpecializedThunkJIT::regT0, nonIntArgJump);
609
610     SpecializedThunkJIT::Label convertedArgumentReentry(&jit);
611     jit.countLeadingZeros32(SpecializedThunkJIT::regT0, SpecializedThunkJIT::regT1);
612     jit.returnInt32(SpecializedThunkJIT::regT1);
613
614     if (jit.supportsFloatingPointTruncate()) {
615         nonIntArgJump.link(&jit);
616         jit.loadDoubleArgument(0, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0);
617         jit.branchTruncateDoubleToInt32(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0, SpecializedThunkJIT::BranchIfTruncateSuccessful).linkTo(convertedArgumentReentry, &jit);
618         jit.appendFailure(jit.jump());
619     } else
620         jit.appendFailure(nonIntArgJump);
621
622     return jit.finalize(vm->jitStubs->ctiNativeTailCall(vm), "clz32");
623 }
624
625 MacroAssemblerCodeRef sqrtThunkGenerator(VM* vm)
626 {
627     SpecializedThunkJIT jit(vm, 1);
628     if (!jit.supportsFloatingPointSqrt())
629         return MacroAssemblerCodeRef::createSelfManagedCodeRef(vm->jitStubs->ctiNativeCall(vm));
630
631     jit.loadDoubleArgument(0, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0);
632     jit.sqrtDouble(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::fpRegT0);
633     jit.returnDouble(SpecializedThunkJIT::fpRegT0);
634     return jit.finalize(vm->jitStubs->ctiNativeTailCall(vm), "sqrt");
635 }
636
637
638 #define UnaryDoubleOpWrapper(function) function##Wrapper
639 enum MathThunkCallingConvention { };
640 typedef MathThunkCallingConvention(*MathThunk)(MathThunkCallingConvention);
641
642 #if CPU(X86_64) && COMPILER(GCC_OR_CLANG) && (OS(DARWIN) || OS(LINUX))
643
644 #define defineUnaryDoubleOpWrapper(function) \
645     asm( \
646         ".text\n" \
647         ".globl " SYMBOL_STRING(function##Thunk) "\n" \
648         HIDE_SYMBOL(function##Thunk) "\n" \
649         SYMBOL_STRING(function##Thunk) ":" "\n" \
650         "pushq %rax\n" \
651         "call " GLOBAL_REFERENCE(function) "\n" \
652         "popq %rcx\n" \
653         "ret\n" \
654     );\
655     extern "C" { \
656         MathThunkCallingConvention function##Thunk(MathThunkCallingConvention); \
657     } \
658     static MathThunk UnaryDoubleOpWrapper(function) = &function##Thunk;
659
660 #elif CPU(X86) && COMPILER(GCC_OR_CLANG) && OS(LINUX) && defined(__PIC__)
661 #define defineUnaryDoubleOpWrapper(function) \
662     asm( \
663         ".text\n" \
664         ".globl " SYMBOL_STRING(function##Thunk) "\n" \
665         HIDE_SYMBOL(function##Thunk) "\n" \
666         SYMBOL_STRING(function##Thunk) ":" "\n" \
667         "pushl %ebx\n" \
668         "subl $20, %esp\n" \
669         "movsd %xmm0, (%esp) \n" \
670         "call __x86.get_pc_thunk.bx\n" \
671         "addl $_GLOBAL_OFFSET_TABLE_, %ebx\n" \
672         "call " GLOBAL_REFERENCE(function) "\n" \
673         "fstpl (%esp) \n" \
674         "movsd (%esp), %xmm0 \n" \
675         "addl $20, %esp\n" \
676         "popl %ebx\n" \
677         "ret\n" \
678     );\
679     extern "C" { \
680         MathThunkCallingConvention function##Thunk(MathThunkCallingConvention); \
681     } \
682     static MathThunk UnaryDoubleOpWrapper(function) = &function##Thunk;
683
684 #elif CPU(X86) && COMPILER(GCC_OR_CLANG) && (OS(DARWIN) || OS(LINUX))
685 #define defineUnaryDoubleOpWrapper(function) \
686     asm( \
687         ".text\n" \
688         ".globl " SYMBOL_STRING(function##Thunk) "\n" \
689         HIDE_SYMBOL(function##Thunk) "\n" \
690         SYMBOL_STRING(function##Thunk) ":" "\n" \
691         "subl $20, %esp\n" \
692         "movsd %xmm0, (%esp) \n" \
693         "call " GLOBAL_REFERENCE(function) "\n" \
694         "fstpl (%esp) \n" \
695         "movsd (%esp), %xmm0 \n" \
696         "addl $20, %esp\n" \
697         "ret\n" \
698     );\
699     extern "C" { \
700         MathThunkCallingConvention function##Thunk(MathThunkCallingConvention); \
701     } \
702     static MathThunk UnaryDoubleOpWrapper(function) = &function##Thunk;
703
704 #elif CPU(ARM_THUMB2) && COMPILER(GCC_OR_CLANG) && PLATFORM(IOS)
705
706 #define defineUnaryDoubleOpWrapper(function) \
707     asm( \
708         ".text\n" \
709         ".align 2\n" \
710         ".globl " SYMBOL_STRING(function##Thunk) "\n" \
711         HIDE_SYMBOL(function##Thunk) "\n" \
712         ".thumb\n" \
713         ".thumb_func " THUMB_FUNC_PARAM(function##Thunk) "\n" \
714         SYMBOL_STRING(function##Thunk) ":" "\n" \
715         "push {lr}\n" \
716         "vmov r0, r1, d0\n" \
717         "blx " GLOBAL_REFERENCE(function) "\n" \
718         "vmov d0, r0, r1\n" \
719         "pop {lr}\n" \
720         "bx lr\n" \
721     ); \
722     extern "C" { \
723         MathThunkCallingConvention function##Thunk(MathThunkCallingConvention); \
724     } \
725     static MathThunk UnaryDoubleOpWrapper(function) = &function##Thunk;
726
727 #elif CPU(ARM64)
728
729 #define defineUnaryDoubleOpWrapper(function) \
730     asm( \
731         ".text\n" \
732         ".align 2\n" \
733         ".globl " SYMBOL_STRING(function##Thunk) "\n" \
734         HIDE_SYMBOL(function##Thunk) "\n" \
735         SYMBOL_STRING(function##Thunk) ":" "\n" \
736         "b " GLOBAL_REFERENCE(function) "\n" \
737         ".previous" \
738     ); \
739     extern "C" { \
740         MathThunkCallingConvention function##Thunk(MathThunkCallingConvention); \
741     } \
742     static MathThunk UnaryDoubleOpWrapper(function) = &function##Thunk;
743
744 #elif CPU(X86) && COMPILER(MSVC) && OS(WINDOWS)
745
746 // MSVC does not accept floor, etc, to be called directly from inline assembly, so we need to wrap these functions.
747 static double (_cdecl *floorFunction)(double) = floor;
748 static double (_cdecl *ceilFunction)(double) = ceil;
749 static double (_cdecl *truncFunction)(double) = trunc;
750 static double (_cdecl *expFunction)(double) = exp;
751 static double (_cdecl *logFunction)(double) = log;
752 static double (_cdecl *jsRoundFunction)(double) = jsRound;
753
754 #define defineUnaryDoubleOpWrapper(function) \
755     extern "C" __declspec(naked) MathThunkCallingConvention function##Thunk(MathThunkCallingConvention) \
756     { \
757         __asm \
758         { \
759         __asm sub esp, 20 \
760         __asm movsd mmword ptr [esp], xmm0  \
761         __asm call function##Function \
762         __asm fstp qword ptr [esp] \
763         __asm movsd xmm0, mmword ptr [esp] \
764         __asm add esp, 20 \
765         __asm ret \
766         } \
767     } \
768     static MathThunk UnaryDoubleOpWrapper(function) = &function##Thunk;
769
770 #else
771
772 #define defineUnaryDoubleOpWrapper(function) \
773     static MathThunk UnaryDoubleOpWrapper(function) = 0
774 #endif
775
776 defineUnaryDoubleOpWrapper(jsRound);
777 defineUnaryDoubleOpWrapper(exp);
778 defineUnaryDoubleOpWrapper(log);
779 defineUnaryDoubleOpWrapper(floor);
780 defineUnaryDoubleOpWrapper(ceil);
781 defineUnaryDoubleOpWrapper(trunc);
782
783 static const double halfConstant = 0.5;
784     
785 MacroAssemblerCodeRef floorThunkGenerator(VM* vm)
786 {
787     SpecializedThunkJIT jit(vm, 1);
788     MacroAssembler::Jump nonIntJump;
789     if (!UnaryDoubleOpWrapper(floor) || !jit.supportsFloatingPoint())
790         return MacroAssemblerCodeRef::createSelfManagedCodeRef(vm->jitStubs->ctiNativeCall(vm));
791     jit.loadInt32Argument(0, SpecializedThunkJIT::regT0, nonIntJump);
792     jit.returnInt32(SpecializedThunkJIT::regT0);
793     nonIntJump.link(&jit);
794     jit.loadDoubleArgument(0, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0);
795
796     if (jit.supportsFloatingPointRounding()) {
797         SpecializedThunkJIT::JumpList doubleResult;
798         jit.floorDouble(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::fpRegT0);
799         jit.branchConvertDoubleToInt32(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0, doubleResult, SpecializedThunkJIT::fpRegT1);
800         jit.returnInt32(SpecializedThunkJIT::regT0);
801         doubleResult.link(&jit);
802         jit.returnDouble(SpecializedThunkJIT::fpRegT0);
803         return jit.finalize(vm->jitStubs->ctiNativeTailCall(vm), "floor");
804     }
805
806     SpecializedThunkJIT::Jump intResult;
807     SpecializedThunkJIT::JumpList doubleResult;
808     if (jit.supportsFloatingPointTruncate()) {
809         jit.moveZeroToDouble(SpecializedThunkJIT::fpRegT1);
810         doubleResult.append(jit.branchDouble(MacroAssembler::DoubleEqual, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::fpRegT1));
811         SpecializedThunkJIT::JumpList slowPath;
812         // Handle the negative doubles in the slow path for now.
813         slowPath.append(jit.branchDouble(MacroAssembler::DoubleLessThanOrUnordered, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::fpRegT1));
814         slowPath.append(jit.branchTruncateDoubleToInt32(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0));
815         intResult = jit.jump();
816         slowPath.link(&jit);
817     }
818     jit.callDoubleToDoublePreservingReturn(UnaryDoubleOpWrapper(floor));
819     jit.branchConvertDoubleToInt32(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0, doubleResult, SpecializedThunkJIT::fpRegT1);
820     if (jit.supportsFloatingPointTruncate())
821         intResult.link(&jit);
822     jit.returnInt32(SpecializedThunkJIT::regT0);
823     doubleResult.link(&jit);
824     jit.returnDouble(SpecializedThunkJIT::fpRegT0);
825     return jit.finalize(vm->jitStubs->ctiNativeTailCall(vm), "floor");
826 }
827
828 MacroAssemblerCodeRef ceilThunkGenerator(VM* vm)
829 {
830     SpecializedThunkJIT jit(vm, 1);
831     if (!UnaryDoubleOpWrapper(ceil) || !jit.supportsFloatingPoint())
832         return MacroAssemblerCodeRef::createSelfManagedCodeRef(vm->jitStubs->ctiNativeCall(vm));
833     MacroAssembler::Jump nonIntJump;
834     jit.loadInt32Argument(0, SpecializedThunkJIT::regT0, nonIntJump);
835     jit.returnInt32(SpecializedThunkJIT::regT0);
836     nonIntJump.link(&jit);
837     jit.loadDoubleArgument(0, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0);
838     if (jit.supportsFloatingPointRounding())
839         jit.ceilDouble(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::fpRegT0);
840     else
841         jit.callDoubleToDoublePreservingReturn(UnaryDoubleOpWrapper(ceil));
842
843     SpecializedThunkJIT::JumpList doubleResult;
844     jit.branchConvertDoubleToInt32(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0, doubleResult, SpecializedThunkJIT::fpRegT1);
845     jit.returnInt32(SpecializedThunkJIT::regT0);
846     doubleResult.link(&jit);
847     jit.returnDouble(SpecializedThunkJIT::fpRegT0);
848     return jit.finalize(vm->jitStubs->ctiNativeTailCall(vm), "ceil");
849 }
850
851 MacroAssemblerCodeRef truncThunkGenerator(VM* vm)
852 {
853     SpecializedThunkJIT jit(vm, 1);
854     if (!UnaryDoubleOpWrapper(trunc) || !jit.supportsFloatingPoint())
855         return MacroAssemblerCodeRef::createSelfManagedCodeRef(vm->jitStubs->ctiNativeCall(vm));
856     MacroAssembler::Jump nonIntJump;
857     jit.loadInt32Argument(0, SpecializedThunkJIT::regT0, nonIntJump);
858     jit.returnInt32(SpecializedThunkJIT::regT0);
859     nonIntJump.link(&jit);
860     jit.loadDoubleArgument(0, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0);
861     if (jit.supportsFloatingPointRounding())
862         jit.roundTowardZeroDouble(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::fpRegT0);
863     else
864         jit.callDoubleToDoublePreservingReturn(UnaryDoubleOpWrapper(trunc));
865
866     SpecializedThunkJIT::JumpList doubleResult;
867     jit.branchConvertDoubleToInt32(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0, doubleResult, SpecializedThunkJIT::fpRegT1);
868     jit.returnInt32(SpecializedThunkJIT::regT0);
869     doubleResult.link(&jit);
870     jit.returnDouble(SpecializedThunkJIT::fpRegT0);
871     return jit.finalize(vm->jitStubs->ctiNativeTailCall(vm), "trunc");
872 }
873
874 MacroAssemblerCodeRef roundThunkGenerator(VM* vm)
875 {
876     SpecializedThunkJIT jit(vm, 1);
877     if (!UnaryDoubleOpWrapper(jsRound) || !jit.supportsFloatingPoint())
878         return MacroAssemblerCodeRef::createSelfManagedCodeRef(vm->jitStubs->ctiNativeCall(vm));
879     MacroAssembler::Jump nonIntJump;
880     jit.loadInt32Argument(0, SpecializedThunkJIT::regT0, nonIntJump);
881     jit.returnInt32(SpecializedThunkJIT::regT0);
882     nonIntJump.link(&jit);
883     jit.loadDoubleArgument(0, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0);
884     SpecializedThunkJIT::Jump intResult;
885     SpecializedThunkJIT::JumpList doubleResult;
886     if (jit.supportsFloatingPointTruncate()) {
887         jit.moveZeroToDouble(SpecializedThunkJIT::fpRegT1);
888         doubleResult.append(jit.branchDouble(MacroAssembler::DoubleEqual, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::fpRegT1));
889         SpecializedThunkJIT::JumpList slowPath;
890         // Handle the negative doubles in the slow path for now.
891         slowPath.append(jit.branchDouble(MacroAssembler::DoubleLessThanOrUnordered, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::fpRegT1));
892         jit.loadDouble(MacroAssembler::TrustedImmPtr(&halfConstant), SpecializedThunkJIT::fpRegT1);
893         jit.addDouble(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::fpRegT1);
894         slowPath.append(jit.branchTruncateDoubleToInt32(SpecializedThunkJIT::fpRegT1, SpecializedThunkJIT::regT0));
895         intResult = jit.jump();
896         slowPath.link(&jit);
897     }
898     jit.callDoubleToDoublePreservingReturn(UnaryDoubleOpWrapper(jsRound));
899     jit.branchConvertDoubleToInt32(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0, doubleResult, SpecializedThunkJIT::fpRegT1);
900     if (jit.supportsFloatingPointTruncate())
901         intResult.link(&jit);
902     jit.returnInt32(SpecializedThunkJIT::regT0);
903     doubleResult.link(&jit);
904     jit.returnDouble(SpecializedThunkJIT::fpRegT0);
905     return jit.finalize(vm->jitStubs->ctiNativeTailCall(vm), "round");
906 }
907
908 MacroAssemblerCodeRef expThunkGenerator(VM* vm)
909 {
910     if (!UnaryDoubleOpWrapper(exp))
911         return MacroAssemblerCodeRef::createSelfManagedCodeRef(vm->jitStubs->ctiNativeCall(vm));
912     SpecializedThunkJIT jit(vm, 1);
913     if (!jit.supportsFloatingPoint())
914         return MacroAssemblerCodeRef::createSelfManagedCodeRef(vm->jitStubs->ctiNativeCall(vm));
915     jit.loadDoubleArgument(0, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0);
916     jit.callDoubleToDoublePreservingReturn(UnaryDoubleOpWrapper(exp));
917     jit.returnDouble(SpecializedThunkJIT::fpRegT0);
918     return jit.finalize(vm->jitStubs->ctiNativeTailCall(vm), "exp");
919 }
920
921 MacroAssemblerCodeRef logThunkGenerator(VM* vm)
922 {
923     if (!UnaryDoubleOpWrapper(log))
924         return MacroAssemblerCodeRef::createSelfManagedCodeRef(vm->jitStubs->ctiNativeCall(vm));
925     SpecializedThunkJIT jit(vm, 1);
926     if (!jit.supportsFloatingPoint())
927         return MacroAssemblerCodeRef::createSelfManagedCodeRef(vm->jitStubs->ctiNativeCall(vm));
928     jit.loadDoubleArgument(0, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0);
929     jit.callDoubleToDoublePreservingReturn(UnaryDoubleOpWrapper(log));
930     jit.returnDouble(SpecializedThunkJIT::fpRegT0);
931     return jit.finalize(vm->jitStubs->ctiNativeTailCall(vm), "log");
932 }
933
934 MacroAssemblerCodeRef absThunkGenerator(VM* vm)
935 {
936     SpecializedThunkJIT jit(vm, 1);
937     if (!jit.supportsFloatingPointAbs())
938         return MacroAssemblerCodeRef::createSelfManagedCodeRef(vm->jitStubs->ctiNativeCall(vm));
939
940 #if USE(JSVALUE64)
941     unsigned virtualRegisterIndex = CallFrame::argumentOffset(0);
942     jit.load64(AssemblyHelpers::addressFor(virtualRegisterIndex), GPRInfo::regT0);
943     MacroAssembler::Jump notInteger = jit.branch64(MacroAssembler::Below, GPRInfo::regT0, GPRInfo::tagTypeNumberRegister);
944
945     // Abs Int32.
946     jit.rshift32(GPRInfo::regT0, MacroAssembler::TrustedImm32(31), GPRInfo::regT1);
947     jit.add32(GPRInfo::regT1, GPRInfo::regT0);
948     jit.xor32(GPRInfo::regT1, GPRInfo::regT0);
949
950     // IntMin cannot be inverted.
951     MacroAssembler::Jump integerIsIntMin = jit.branchTest32(MacroAssembler::Signed, GPRInfo::regT0);
952
953     // Box and finish.
954     jit.or64(GPRInfo::tagTypeNumberRegister, GPRInfo::regT0);
955     MacroAssembler::Jump doneWithIntegers = jit.jump();
956
957     // Handle Doubles.
958     notInteger.link(&jit);
959     jit.appendFailure(jit.branchTest64(MacroAssembler::Zero, GPRInfo::regT0, GPRInfo::tagTypeNumberRegister));
960     jit.unboxDoubleWithoutAssertions(GPRInfo::regT0, GPRInfo::regT0, FPRInfo::fpRegT0);
961     MacroAssembler::Label absFPR0Label = jit.label();
962     jit.absDouble(FPRInfo::fpRegT0, FPRInfo::fpRegT1);
963     jit.boxDouble(FPRInfo::fpRegT1, GPRInfo::regT0);
964
965     // Tail.
966     doneWithIntegers.link(&jit);
967     jit.returnJSValue(GPRInfo::regT0);
968
969     // We know the value of regT0 is IntMin. We could load that value from memory but
970     // it is simpler to just convert it.
971     integerIsIntMin.link(&jit);
972     jit.convertInt32ToDouble(GPRInfo::regT0, FPRInfo::fpRegT0);
973     jit.jump().linkTo(absFPR0Label, &jit);
974 #else
975     MacroAssembler::Jump nonIntJump;
976     jit.loadInt32Argument(0, SpecializedThunkJIT::regT0, nonIntJump);
977     jit.rshift32(SpecializedThunkJIT::regT0, MacroAssembler::TrustedImm32(31), SpecializedThunkJIT::regT1);
978     jit.add32(SpecializedThunkJIT::regT1, SpecializedThunkJIT::regT0);
979     jit.xor32(SpecializedThunkJIT::regT1, SpecializedThunkJIT::regT0);
980     jit.appendFailure(jit.branchTest32(MacroAssembler::Signed, SpecializedThunkJIT::regT0));
981     jit.returnInt32(SpecializedThunkJIT::regT0);
982     nonIntJump.link(&jit);
983     // Shame about the double int conversion here.
984     jit.loadDoubleArgument(0, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0);
985     jit.absDouble(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::fpRegT1);
986     jit.returnDouble(SpecializedThunkJIT::fpRegT1);
987 #endif
988     return jit.finalize(vm->jitStubs->ctiNativeTailCall(vm), "abs");
989 }
990
991 MacroAssemblerCodeRef imulThunkGenerator(VM* vm)
992 {
993     SpecializedThunkJIT jit(vm, 2);
994     MacroAssembler::Jump nonIntArg0Jump;
995     jit.loadInt32Argument(0, SpecializedThunkJIT::regT0, nonIntArg0Jump);
996     SpecializedThunkJIT::Label doneLoadingArg0(&jit);
997     MacroAssembler::Jump nonIntArg1Jump;
998     jit.loadInt32Argument(1, SpecializedThunkJIT::regT1, nonIntArg1Jump);
999     SpecializedThunkJIT::Label doneLoadingArg1(&jit);
1000     jit.mul32(SpecializedThunkJIT::regT1, SpecializedThunkJIT::regT0);
1001     jit.returnInt32(SpecializedThunkJIT::regT0);
1002
1003     if (jit.supportsFloatingPointTruncate()) {
1004         nonIntArg0Jump.link(&jit);
1005         jit.loadDoubleArgument(0, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0);
1006         jit.branchTruncateDoubleToInt32(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0, SpecializedThunkJIT::BranchIfTruncateSuccessful).linkTo(doneLoadingArg0, &jit);
1007         jit.appendFailure(jit.jump());
1008     } else
1009         jit.appendFailure(nonIntArg0Jump);
1010
1011     if (jit.supportsFloatingPointTruncate()) {
1012         nonIntArg1Jump.link(&jit);
1013         jit.loadDoubleArgument(1, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT1);
1014         jit.branchTruncateDoubleToInt32(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT1, SpecializedThunkJIT::BranchIfTruncateSuccessful).linkTo(doneLoadingArg1, &jit);
1015         jit.appendFailure(jit.jump());
1016     } else
1017         jit.appendFailure(nonIntArg1Jump);
1018
1019     return jit.finalize(vm->jitStubs->ctiNativeTailCall(vm), "imul");
1020 }
1021
1022 MacroAssemblerCodeRef randomThunkGenerator(VM* vm)
1023 {
1024     SpecializedThunkJIT jit(vm, 0);
1025     if (!jit.supportsFloatingPoint())
1026         return MacroAssemblerCodeRef::createSelfManagedCodeRef(vm->jitStubs->ctiNativeCall(vm));
1027
1028 #if USE(JSVALUE64)
1029     jit.emitRandomThunk(SpecializedThunkJIT::regT0, SpecializedThunkJIT::regT1, SpecializedThunkJIT::regT2, SpecializedThunkJIT::regT3, SpecializedThunkJIT::fpRegT0);
1030     jit.returnDouble(SpecializedThunkJIT::fpRegT0);
1031
1032     return jit.finalize(vm->jitStubs->ctiNativeTailCall(vm), "random");
1033 #else
1034     return MacroAssemblerCodeRef::createSelfManagedCodeRef(vm->jitStubs->ctiNativeCall(vm));
1035 #endif
1036 }
1037
1038 MacroAssemblerCodeRef boundThisNoArgsFunctionCallGenerator(VM* vm)
1039 {
1040     CCallHelpers jit(vm);
1041     
1042     jit.emitFunctionPrologue();
1043     
1044     // Set up our call frame.
1045     jit.storePtr(CCallHelpers::TrustedImmPtr(nullptr), CCallHelpers::addressFor(CallFrameSlot::codeBlock));
1046     jit.store32(CCallHelpers::TrustedImm32(0), CCallHelpers::tagFor(CallFrameSlot::argumentCount));
1047
1048     unsigned extraStackNeeded = 0;
1049     if (unsigned stackMisalignment = sizeof(CallerFrameAndPC) % stackAlignmentBytes())
1050         extraStackNeeded = stackAlignmentBytes() - stackMisalignment;
1051     
1052     // We need to forward all of the arguments that we were passed. We aren't allowed to do a tail
1053     // call here as far as I can tell. At least not so long as the generic path doesn't do a tail
1054     // call, since that would be way too weird.
1055     
1056     // The formula for the number of stack bytes needed given some number of parameters (including
1057     // this) is:
1058     //
1059     //     stackAlign((numParams + CallFrameHeaderSize) * sizeof(Register) - sizeof(CallerFrameAndPC))
1060     //
1061     // Probably we want to write this as:
1062     //
1063     //     stackAlign((numParams + (CallFrameHeaderSize - CallerFrameAndPCSize)) * sizeof(Register))
1064     //
1065     // That's really all there is to this. We have all the registers we need to do it.
1066     
1067     jit.load32(CCallHelpers::payloadFor(CallFrameSlot::argumentCount), GPRInfo::regT1);
1068     jit.add32(CCallHelpers::TrustedImm32(CallFrame::headerSizeInRegisters - CallerFrameAndPC::sizeInRegisters), GPRInfo::regT1, GPRInfo::regT2);
1069     jit.lshift32(CCallHelpers::TrustedImm32(3), GPRInfo::regT2);
1070     jit.add32(CCallHelpers::TrustedImm32(stackAlignmentBytes() - 1), GPRInfo::regT2);
1071     jit.and32(CCallHelpers::TrustedImm32(-stackAlignmentBytes()), GPRInfo::regT2);
1072     
1073     if (extraStackNeeded)
1074         jit.add32(CCallHelpers::TrustedImm32(extraStackNeeded), GPRInfo::regT2);
1075     
1076     // At this point regT1 has the actual argument count and regT2 has the amount of stack we will
1077     // need.
1078     
1079     jit.subPtr(GPRInfo::regT2, CCallHelpers::stackPointerRegister);
1080
1081     // Do basic callee frame setup, including 'this'.
1082     
1083     jit.loadCell(CCallHelpers::addressFor(CallFrameSlot::callee), GPRInfo::regT3);
1084
1085     jit.store32(GPRInfo::regT1, CCallHelpers::calleeFramePayloadSlot(CallFrameSlot::argumentCount));
1086     
1087     JSValueRegs valueRegs = JSValueRegs::withTwoAvailableRegs(GPRInfo::regT0, GPRInfo::regT2);
1088     jit.loadValue(CCallHelpers::Address(GPRInfo::regT3, JSBoundFunction::offsetOfBoundThis()), valueRegs);
1089     jit.storeValue(valueRegs, CCallHelpers::calleeArgumentSlot(0));
1090
1091     jit.loadPtr(CCallHelpers::Address(GPRInfo::regT3, JSBoundFunction::offsetOfTargetFunction()), GPRInfo::regT3);
1092     jit.storeCell(GPRInfo::regT3, CCallHelpers::calleeFrameSlot(CallFrameSlot::callee));
1093     
1094     // OK, now we can start copying. This is a simple matter of copying parameters from the caller's
1095     // frame to the callee's frame. Note that we know that regT1 (the argument count) must be at
1096     // least 1.
1097     jit.sub32(CCallHelpers::TrustedImm32(1), GPRInfo::regT1);
1098     CCallHelpers::Jump done = jit.branchTest32(CCallHelpers::Zero, GPRInfo::regT1);
1099     
1100     CCallHelpers::Label loop = jit.label();
1101     jit.sub32(CCallHelpers::TrustedImm32(1), GPRInfo::regT1);
1102     jit.loadValue(CCallHelpers::addressFor(virtualRegisterForArgument(1)).indexedBy(GPRInfo::regT1, CCallHelpers::TimesEight), valueRegs);
1103     jit.storeValue(valueRegs, CCallHelpers::calleeArgumentSlot(1).indexedBy(GPRInfo::regT1, CCallHelpers::TimesEight));
1104     jit.branchTest32(CCallHelpers::NonZero, GPRInfo::regT1).linkTo(loop, &jit);
1105     
1106     done.link(&jit);
1107     
1108     jit.loadPtr(
1109         CCallHelpers::Address(GPRInfo::regT3, JSFunction::offsetOfExecutable()),
1110         GPRInfo::regT0);
1111     jit.loadPtr(
1112         CCallHelpers::Address(
1113             GPRInfo::regT0, ExecutableBase::offsetOfJITCodeWithArityCheckFor(CodeForCall)),
1114         GPRInfo::regT0);
1115     CCallHelpers::Jump noCode = jit.branchTestPtr(CCallHelpers::Zero, GPRInfo::regT0);
1116     
1117     emitPointerValidation(jit, GPRInfo::regT0);
1118     jit.call(GPRInfo::regT0);
1119     
1120     jit.emitFunctionEpilogue();
1121     jit.ret();
1122     
1123     LinkBuffer linkBuffer(*vm, jit, GLOBAL_THUNK_ID);
1124     linkBuffer.link(noCode, CodeLocationLabel(vm->jitStubs->ctiNativeTailCallWithoutSavedTags(vm)));
1125     return FINALIZE_CODE(
1126         linkBuffer, ("Specialized thunk for bound function calls with no arguments"));
1127 }
1128
1129 } // namespace JSC
1130
1131 #endif // ENABLE(JIT)