DFG should really support varargs
[WebKit-https.git] / Source / JavaScriptCore / jit / AssemblyHelpers.h
1 /*
2  * Copyright (C) 2011, 2013-2015 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #ifndef AssemblyHelpers_h
27 #define AssemblyHelpers_h
28
29 #if ENABLE(JIT)
30
31 #include "CodeBlock.h"
32 #include "FPRInfo.h"
33 #include "GPRInfo.h"
34 #include "JITCode.h"
35 #include "MacroAssembler.h"
36 #include "VM.h"
37
38 namespace JSC {
39
40 typedef void (*V_DebugOperation_EPP)(ExecState*, void*, void*);
41
42 class AssemblyHelpers : public MacroAssembler {
43 public:
44     AssemblyHelpers(VM* vm, CodeBlock* codeBlock)
45         : m_vm(vm)
46         , m_codeBlock(codeBlock)
47         , m_baselineCodeBlock(codeBlock ? codeBlock->baselineAlternative() : 0)
48     {
49         if (m_codeBlock) {
50             ASSERT(m_baselineCodeBlock);
51             ASSERT(!m_baselineCodeBlock->alternative());
52             ASSERT(m_baselineCodeBlock->jitType() == JITCode::None || JITCode::isBaselineCode(m_baselineCodeBlock->jitType()));
53         }
54     }
55     
56     CodeBlock* codeBlock() { return m_codeBlock; }
57     VM* vm() { return m_vm; }
58     AssemblerType_T& assembler() { return m_assembler; }
59
60     void checkStackPointerAlignment()
61     {
62         // This check is both unneeded and harder to write correctly for ARM64
63 #if !defined(NDEBUG) && !CPU(ARM64)
64         Jump stackPointerAligned = branchTestPtr(Zero, stackPointerRegister, TrustedImm32(0xf));
65         abortWithReason(AHStackPointerMisaligned);
66         stackPointerAligned.link(this);
67 #endif
68     }
69     
70     template<typename T>
71     void storeCell(T cell, Address address)
72     {
73 #if USE(JSVALUE64)
74         store64(cell, address);
75 #else
76         store32(cell, address.withOffset(PayloadOffset));
77         store32(TrustedImm32(JSValue::CellTag), address.withOffset(TagOffset));
78 #endif
79     }
80     
81     void storeValue(JSValueRegs regs, Address address)
82     {
83 #if USE(JSVALUE64)
84         store64(regs.gpr(), address);
85 #else
86         store32(regs.payloadGPR(), address.withOffset(PayloadOffset));
87         store32(regs.tagGPR(), address.withOffset(TagOffset));
88 #endif
89     }
90     
91     void storeValue(JSValueRegs regs, void* address)
92     {
93 #if USE(JSVALUE64)
94         store64(regs.gpr(), address);
95 #else
96         store32(regs.payloadGPR(), bitwise_cast<void*>(bitwise_cast<uintptr_t>(address) + PayloadOffset));
97         store32(regs.tagGPR(), bitwise_cast<void*>(bitwise_cast<uintptr_t>(address) + TagOffset));
98 #endif
99     }
100     
101     void loadValue(Address address, JSValueRegs regs)
102     {
103 #if USE(JSVALUE64)
104         load64(address, regs.gpr());
105 #else
106         if (address.base == regs.payloadGPR()) {
107             load32(address.withOffset(TagOffset), regs.tagGPR());
108             load32(address.withOffset(PayloadOffset), regs.payloadGPR());
109         } else {
110             load32(address.withOffset(PayloadOffset), regs.payloadGPR());
111             load32(address.withOffset(TagOffset), regs.tagGPR());
112         }
113 #endif
114     }
115     
116     void moveTrustedValue(JSValue value, JSValueRegs regs)
117     {
118 #if USE(JSVALUE64)
119         move(TrustedImm64(JSValue::encode(value)), regs.gpr());
120 #else
121         move(TrustedImm32(value.tag()), regs.tagGPR());
122         move(TrustedImm32(value.payload()), regs.payloadGPR());
123 #endif
124     }
125
126 #if CPU(X86_64) || CPU(X86)
127     static size_t prologueStackPointerDelta()
128     {
129         // Prologue only saves the framePointerRegister
130         return sizeof(void*);
131     }
132
133     void emitFunctionPrologue()
134     {
135         push(framePointerRegister);
136         move(stackPointerRegister, framePointerRegister);
137     }
138
139     void emitFunctionEpilogue()
140     {
141         move(framePointerRegister, stackPointerRegister);
142         pop(framePointerRegister);
143     }
144
145     void preserveReturnAddressAfterCall(GPRReg reg)
146     {
147         pop(reg);
148     }
149
150     void restoreReturnAddressBeforeReturn(GPRReg reg)
151     {
152         push(reg);
153     }
154
155     void restoreReturnAddressBeforeReturn(Address address)
156     {
157         push(address);
158     }
159 #endif // CPU(X86_64) || CPU(X86)
160
161 #if CPU(ARM) || CPU(ARM64)
162     static size_t prologueStackPointerDelta()
163     {
164         // Prologue saves the framePointerRegister and linkRegister
165         return 2 * sizeof(void*);
166     }
167
168     void emitFunctionPrologue()
169     {
170         pushPair(framePointerRegister, linkRegister);
171         move(stackPointerRegister, framePointerRegister);
172     }
173
174     void emitFunctionEpilogue()
175     {
176         move(framePointerRegister, stackPointerRegister);
177         popPair(framePointerRegister, linkRegister);
178     }
179
180     ALWAYS_INLINE void preserveReturnAddressAfterCall(RegisterID reg)
181     {
182         move(linkRegister, reg);
183     }
184
185     ALWAYS_INLINE void restoreReturnAddressBeforeReturn(RegisterID reg)
186     {
187         move(reg, linkRegister);
188     }
189
190     ALWAYS_INLINE void restoreReturnAddressBeforeReturn(Address address)
191     {
192         loadPtr(address, linkRegister);
193     }
194 #endif
195
196 #if CPU(MIPS)
197     static size_t prologueStackPointerDelta()
198     {
199         // Prologue saves the framePointerRegister and returnAddressRegister
200         return 2 * sizeof(void*);
201     }
202
203     ALWAYS_INLINE void preserveReturnAddressAfterCall(RegisterID reg)
204     {
205         move(returnAddressRegister, reg);
206     }
207
208     ALWAYS_INLINE void restoreReturnAddressBeforeReturn(RegisterID reg)
209     {
210         move(reg, returnAddressRegister);
211     }
212
213     ALWAYS_INLINE void restoreReturnAddressBeforeReturn(Address address)
214     {
215         loadPtr(address, returnAddressRegister);
216     }
217 #endif
218
219 #if CPU(SH4)
220     static size_t prologueStackPointerDelta()
221     {
222         // Prologue saves the framePointerRegister and link register
223         return 2 * sizeof(void*);
224     }
225
226     void emitFunctionPrologue()
227     {
228         push(linkRegister);
229         push(framePointerRegister);
230         move(stackPointerRegister, framePointerRegister);
231     }
232
233     void emitFunctionEpilogue()
234     {
235         move(framePointerRegister, stackPointerRegister);
236         pop(framePointerRegister);
237         pop(linkRegister);
238     }
239
240     ALWAYS_INLINE void preserveReturnAddressAfterCall(RegisterID reg)
241     {
242         m_assembler.stspr(reg);
243     }
244
245     ALWAYS_INLINE void restoreReturnAddressBeforeReturn(RegisterID reg)
246     {
247         m_assembler.ldspr(reg);
248     }
249
250     ALWAYS_INLINE void restoreReturnAddressBeforeReturn(Address address)
251     {
252         loadPtrLinkReg(address);
253     }
254 #endif
255
256     void emitGetFromCallFrameHeaderPtr(JSStack::CallFrameHeaderEntry entry, GPRReg to, GPRReg from = GPRInfo::callFrameRegister)
257     {
258         loadPtr(Address(from, entry * sizeof(Register)), to);
259     }
260     void emitGetFromCallFrameHeader32(JSStack::CallFrameHeaderEntry entry, GPRReg to, GPRReg from = GPRInfo::callFrameRegister)
261     {
262         load32(Address(from, entry * sizeof(Register)), to);
263     }
264 #if USE(JSVALUE64)
265     void emitGetFromCallFrameHeader64(JSStack::CallFrameHeaderEntry entry, GPRReg to, GPRReg from = GPRInfo::callFrameRegister)
266     {
267         load64(Address(from, entry * sizeof(Register)), to);
268     }
269 #endif // USE(JSVALUE64)
270     void emitPutToCallFrameHeader(GPRReg from, JSStack::CallFrameHeaderEntry entry)
271     {
272         storePtr(from, Address(GPRInfo::callFrameRegister, entry * sizeof(Register)));
273     }
274
275     void emitPutImmediateToCallFrameHeader(void* value, JSStack::CallFrameHeaderEntry entry)
276     {
277         storePtr(TrustedImmPtr(value), Address(GPRInfo::callFrameRegister, entry * sizeof(Register)));
278     }
279
280     void emitGetCallerFrameFromCallFrameHeaderPtr(RegisterID to)
281     {
282         loadPtr(Address(GPRInfo::callFrameRegister, CallFrame::callerFrameOffset()), to);
283     }
284     void emitPutCallerFrameToCallFrameHeader(RegisterID from)
285     {
286         storePtr(from, Address(GPRInfo::callFrameRegister, CallFrame::callerFrameOffset()));
287     }
288
289     void emitPutReturnPCToCallFrameHeader(RegisterID from)
290     {
291         storePtr(from, Address(GPRInfo::callFrameRegister, CallFrame::returnPCOffset()));
292     }
293     void emitPutReturnPCToCallFrameHeader(TrustedImmPtr from)
294     {
295         storePtr(from, Address(GPRInfo::callFrameRegister, CallFrame::returnPCOffset()));
296     }
297
298     // emitPutToCallFrameHeaderBeforePrologue() and related are used to access callee frame header
299     // fields before the code from emitFunctionPrologue() has executed.
300     // First, the access is via the stack pointer. Second, the address calculation must also take
301     // into account that the stack pointer may not have been adjusted down for the return PC and/or
302     // caller's frame pointer. On some platforms, the callee is responsible for pushing the
303     // "link register" containing the return address in the function prologue.
304 #if USE(JSVALUE64)
305     void emitPutToCallFrameHeaderBeforePrologue(GPRReg from, JSStack::CallFrameHeaderEntry entry)
306     {
307         storePtr(from, Address(stackPointerRegister, entry * static_cast<ptrdiff_t>(sizeof(Register)) - prologueStackPointerDelta()));
308     }
309 #else
310     void emitPutPayloadToCallFrameHeaderBeforePrologue(GPRReg from, JSStack::CallFrameHeaderEntry entry)
311     {
312         storePtr(from, Address(stackPointerRegister, entry * static_cast<ptrdiff_t>(sizeof(Register)) - prologueStackPointerDelta() + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
313     }
314
315     void emitPutTagToCallFrameHeaderBeforePrologue(TrustedImm32 tag, JSStack::CallFrameHeaderEntry entry)
316     {
317         storePtr(tag, Address(stackPointerRegister, entry * static_cast<ptrdiff_t>(sizeof(Register)) - prologueStackPointerDelta() + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
318     }
319 #endif
320
321     Jump branchIfNotCell(GPRReg reg)
322     {
323 #if USE(JSVALUE64)
324         return branchTest64(MacroAssembler::NonZero, reg, GPRInfo::tagMaskRegister);
325 #else
326         return branch32(MacroAssembler::NotEqual, reg, TrustedImm32(JSValue::CellTag));
327 #endif
328     }
329     
330     static Address addressForByteOffset(ptrdiff_t byteOffset)
331     {
332         return Address(GPRInfo::callFrameRegister, byteOffset);
333     }
334     static Address addressFor(VirtualRegister virtualRegister, GPRReg baseReg)
335     {
336         ASSERT(virtualRegister.isValid());
337         return Address(baseReg, virtualRegister.offset() * sizeof(Register));
338     }
339     static Address addressFor(VirtualRegister virtualRegister)
340     {
341         // NB. It's tempting on some architectures to sometimes use an offset from the stack
342         // register because for some offsets that will encode to a smaller instruction. But we
343         // cannot do this. We use this in places where the stack pointer has been moved to some
344         // unpredictable location.
345         ASSERT(virtualRegister.isValid());
346         return Address(GPRInfo::callFrameRegister, virtualRegister.offset() * sizeof(Register));
347     }
348     static Address addressFor(int operand)
349     {
350         return addressFor(static_cast<VirtualRegister>(operand));
351     }
352
353     static Address tagFor(VirtualRegister virtualRegister)
354     {
355         ASSERT(virtualRegister.isValid());
356         return Address(GPRInfo::callFrameRegister, virtualRegister.offset() * sizeof(Register) + TagOffset);
357     }
358     static Address tagFor(int operand)
359     {
360         return tagFor(static_cast<VirtualRegister>(operand));
361     }
362
363     static Address payloadFor(VirtualRegister virtualRegister)
364     {
365         ASSERT(virtualRegister.isValid());
366         return Address(GPRInfo::callFrameRegister, virtualRegister.offset() * sizeof(Register) + PayloadOffset);
367     }
368     static Address payloadFor(int operand)
369     {
370         return payloadFor(static_cast<VirtualRegister>(operand));
371     }
372
373     // Access to our fixed callee CallFrame.
374     static Address calleeFrameSlot(int slot)
375     {
376         ASSERT(slot >= JSStack::CallerFrameAndPCSize);
377         return Address(stackPointerRegister, sizeof(Register) * (slot - JSStack::CallerFrameAndPCSize));
378     }
379
380     // Access to our fixed callee CallFrame.
381     static Address calleeArgumentSlot(int argument)
382     {
383         return calleeFrameSlot(virtualRegisterForArgument(argument).offset());
384     }
385
386     static Address calleeFrameTagSlot(int slot)
387     {
388         return calleeFrameSlot(slot).withOffset(TagOffset);
389     }
390
391     static Address calleeFramePayloadSlot(int slot)
392     {
393         return calleeFrameSlot(slot).withOffset(PayloadOffset);
394     }
395
396     static Address calleeArgumentTagSlot(int argument)
397     {
398         return calleeArgumentSlot(argument).withOffset(TagOffset);
399     }
400
401     static Address calleeArgumentPayloadSlot(int argument)
402     {
403         return calleeArgumentSlot(argument).withOffset(PayloadOffset);
404     }
405
406     static Address calleeFrameCallerFrame()
407     {
408         return calleeFrameSlot(0).withOffset(CallFrame::callerFrameOffset());
409     }
410
411     Jump branchIfCellNotObject(GPRReg cellReg)
412     {
413         return branch8(Below, Address(cellReg, JSCell::typeInfoTypeOffset()), TrustedImm32(ObjectType));
414     }
415
416     static GPRReg selectScratchGPR(GPRReg preserve1 = InvalidGPRReg, GPRReg preserve2 = InvalidGPRReg, GPRReg preserve3 = InvalidGPRReg, GPRReg preserve4 = InvalidGPRReg, GPRReg preserve5 = InvalidGPRReg)
417     {
418         if (preserve1 != GPRInfo::regT0 && preserve2 != GPRInfo::regT0 && preserve3 != GPRInfo::regT0 && preserve4 != GPRInfo::regT0 && preserve5 != GPRInfo::regT0)
419             return GPRInfo::regT0;
420
421         if (preserve1 != GPRInfo::regT1 && preserve2 != GPRInfo::regT1 && preserve3 != GPRInfo::regT1 && preserve4 != GPRInfo::regT1 && preserve5 != GPRInfo::regT1)
422             return GPRInfo::regT1;
423
424         if (preserve1 != GPRInfo::regT2 && preserve2 != GPRInfo::regT2 && preserve3 != GPRInfo::regT2 && preserve4 != GPRInfo::regT2 && preserve5 != GPRInfo::regT2)
425             return GPRInfo::regT2;
426
427         if (preserve1 != GPRInfo::regT3 && preserve2 != GPRInfo::regT3 && preserve3 != GPRInfo::regT3 && preserve4 != GPRInfo::regT3 && preserve5 != GPRInfo::regT3)
428             return GPRInfo::regT3;
429
430         if (preserve1 != GPRInfo::regT4 && preserve2 != GPRInfo::regT4 && preserve3 != GPRInfo::regT4 && preserve4 != GPRInfo::regT4 && preserve5 != GPRInfo::regT4)
431             return GPRInfo::regT4;
432
433         return GPRInfo::regT5;
434     }
435
436     // Add a debug call. This call has no effect on JIT code execution state.
437     void debugCall(V_DebugOperation_EPP function, void* argument)
438     {
439         size_t scratchSize = sizeof(EncodedJSValue) * (GPRInfo::numberOfRegisters + FPRInfo::numberOfRegisters);
440         ScratchBuffer* scratchBuffer = m_vm->scratchBufferForSize(scratchSize);
441         EncodedJSValue* buffer = static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer());
442
443         for (unsigned i = 0; i < GPRInfo::numberOfRegisters; ++i) {
444 #if USE(JSVALUE64)
445             store64(GPRInfo::toRegister(i), buffer + i);
446 #else
447             store32(GPRInfo::toRegister(i), buffer + i);
448 #endif
449         }
450
451         for (unsigned i = 0; i < FPRInfo::numberOfRegisters; ++i) {
452             move(TrustedImmPtr(buffer + GPRInfo::numberOfRegisters + i), GPRInfo::regT0);
453             storeDouble(FPRInfo::toRegister(i), GPRInfo::regT0);
454         }
455
456         // Tell GC mark phase how much of the scratch buffer is active during call.
457         move(TrustedImmPtr(scratchBuffer->activeLengthPtr()), GPRInfo::regT0);
458         storePtr(TrustedImmPtr(scratchSize), GPRInfo::regT0);
459
460 #if CPU(X86_64) || CPU(ARM) || CPU(ARM64) || CPU(MIPS) || CPU(SH4)
461         move(TrustedImmPtr(buffer), GPRInfo::argumentGPR2);
462         move(TrustedImmPtr(argument), GPRInfo::argumentGPR1);
463         move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
464         GPRReg scratch = selectScratchGPR(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1, GPRInfo::argumentGPR2);
465 #elif CPU(X86)
466         poke(GPRInfo::callFrameRegister, 0);
467         poke(TrustedImmPtr(argument), 1);
468         poke(TrustedImmPtr(buffer), 2);
469         GPRReg scratch = GPRInfo::regT0;
470 #else
471 #error "JIT not supported on this platform."
472 #endif
473         move(TrustedImmPtr(reinterpret_cast<void*>(function)), scratch);
474         call(scratch);
475
476         move(TrustedImmPtr(scratchBuffer->activeLengthPtr()), GPRInfo::regT0);
477         storePtr(TrustedImmPtr(0), GPRInfo::regT0);
478
479         for (unsigned i = 0; i < FPRInfo::numberOfRegisters; ++i) {
480             move(TrustedImmPtr(buffer + GPRInfo::numberOfRegisters + i), GPRInfo::regT0);
481             loadDouble(GPRInfo::regT0, FPRInfo::toRegister(i));
482         }
483         for (unsigned i = 0; i < GPRInfo::numberOfRegisters; ++i) {
484 #if USE(JSVALUE64)
485             load64(buffer + i, GPRInfo::toRegister(i));
486 #else
487             load32(buffer + i, GPRInfo::toRegister(i));
488 #endif
489         }
490     }
491
492     // These methods JIT generate dynamic, debug-only checks - akin to ASSERTs.
493 #if !ASSERT_DISABLED
494     void jitAssertIsInt32(GPRReg);
495     void jitAssertIsJSInt32(GPRReg);
496     void jitAssertIsJSNumber(GPRReg);
497     void jitAssertIsJSDouble(GPRReg);
498     void jitAssertIsCell(GPRReg);
499     void jitAssertHasValidCallFrame();
500     void jitAssertIsNull(GPRReg);
501     void jitAssertTagsInPlace();
502     void jitAssertArgumentCountSane();
503 #else
504     void jitAssertIsInt32(GPRReg) { }
505     void jitAssertIsJSInt32(GPRReg) { }
506     void jitAssertIsJSNumber(GPRReg) { }
507     void jitAssertIsJSDouble(GPRReg) { }
508     void jitAssertIsCell(GPRReg) { }
509     void jitAssertHasValidCallFrame() { }
510     void jitAssertIsNull(GPRReg) { }
511     void jitAssertTagsInPlace() { }
512     void jitAssertArgumentCountSane() { }
513 #endif
514     
515     void purifyNaN(FPRReg);
516
517     // These methods convert between doubles, and doubles boxed and JSValues.
518 #if USE(JSVALUE64)
519     GPRReg boxDouble(FPRReg fpr, GPRReg gpr)
520     {
521         moveDoubleTo64(fpr, gpr);
522         sub64(GPRInfo::tagTypeNumberRegister, gpr);
523         jitAssertIsJSDouble(gpr);
524         return gpr;
525     }
526     FPRReg unboxDouble(GPRReg gpr, FPRReg fpr)
527     {
528         jitAssertIsJSDouble(gpr);
529         add64(GPRInfo::tagTypeNumberRegister, gpr);
530         move64ToDouble(gpr, fpr);
531         return fpr;
532     }
533     
534     void boxDouble(FPRReg fpr, JSValueRegs regs)
535     {
536         boxDouble(fpr, regs.gpr());
537     }
538     
539     // Here are possible arrangements of source, target, scratch:
540     // - source, target, scratch can all be separate registers.
541     // - source and target can be the same but scratch is separate.
542     // - target and scratch can be the same but source is separate.
543     void boxInt52(GPRReg source, GPRReg target, GPRReg scratch, FPRReg fpScratch)
544     {
545         // Is it an int32?
546         signExtend32ToPtr(source, scratch);
547         Jump isInt32 = branch64(Equal, source, scratch);
548         
549         // Nope, it's not, but regT0 contains the int64 value.
550         convertInt64ToDouble(source, fpScratch);
551         boxDouble(fpScratch, target);
552         Jump done = jump();
553         
554         isInt32.link(this);
555         zeroExtend32ToPtr(source, target);
556         or64(GPRInfo::tagTypeNumberRegister, target);
557         
558         done.link(this);
559     }
560 #endif
561
562 #if USE(JSVALUE32_64)
563     void boxDouble(FPRReg fpr, GPRReg tagGPR, GPRReg payloadGPR)
564     {
565         moveDoubleToInts(fpr, payloadGPR, tagGPR);
566     }
567     void unboxDouble(GPRReg tagGPR, GPRReg payloadGPR, FPRReg fpr, FPRReg scratchFPR)
568     {
569         moveIntsToDouble(payloadGPR, tagGPR, fpr, scratchFPR);
570     }
571     
572     void boxDouble(FPRReg fpr, JSValueRegs regs)
573     {
574         boxDouble(fpr, regs.tagGPR(), regs.payloadGPR());
575     }
576 #endif
577     
578     void callExceptionFuzz();
579     
580     enum ExceptionCheckKind { NormalExceptionCheck, InvertedExceptionCheck };
581     enum ExceptionJumpWidth { NormalJumpWidth, FarJumpWidth };
582     Jump emitExceptionCheck(
583         ExceptionCheckKind = NormalExceptionCheck, ExceptionJumpWidth = NormalJumpWidth);
584
585 #if ENABLE(SAMPLING_COUNTERS)
586     static void emitCount(MacroAssembler& jit, AbstractSamplingCounter& counter, int32_t increment = 1)
587     {
588         jit.add64(TrustedImm32(increment), AbsoluteAddress(counter.addressOfCounter()));
589     }
590     void emitCount(AbstractSamplingCounter& counter, int32_t increment = 1)
591     {
592         add64(TrustedImm32(increment), AbsoluteAddress(counter.addressOfCounter()));
593     }
594 #endif
595
596 #if ENABLE(SAMPLING_FLAGS)
597     void setSamplingFlag(int32_t);
598     void clearSamplingFlag(int32_t flag);
599 #endif
600
601     JSGlobalObject* globalObjectFor(CodeOrigin codeOrigin)
602     {
603         return codeBlock()->globalObjectFor(codeOrigin);
604     }
605     
606     bool isStrictModeFor(CodeOrigin codeOrigin)
607     {
608         if (!codeOrigin.inlineCallFrame)
609             return codeBlock()->isStrictMode();
610         return jsCast<FunctionExecutable*>(codeOrigin.inlineCallFrame->executable.get())->isStrictMode();
611     }
612     
613     ECMAMode ecmaModeFor(CodeOrigin codeOrigin)
614     {
615         return isStrictModeFor(codeOrigin) ? StrictMode : NotStrictMode;
616     }
617     
618     ExecutableBase* executableFor(const CodeOrigin& codeOrigin);
619     
620     CodeBlock* baselineCodeBlockFor(const CodeOrigin& codeOrigin)
621     {
622         return baselineCodeBlockForOriginAndBaselineCodeBlock(codeOrigin, baselineCodeBlock());
623     }
624     
625     CodeBlock* baselineCodeBlockFor(InlineCallFrame* inlineCallFrame)
626     {
627         if (!inlineCallFrame)
628             return baselineCodeBlock();
629         return baselineCodeBlockForInlineCallFrame(inlineCallFrame);
630     }
631     
632     CodeBlock* baselineCodeBlock()
633     {
634         return m_baselineCodeBlock;
635     }
636     
637     VirtualRegister baselineArgumentsRegisterFor(InlineCallFrame* inlineCallFrame)
638     {
639         if (!inlineCallFrame)
640             return baselineCodeBlock()->argumentsRegister();
641         
642         return VirtualRegister(baselineCodeBlockForInlineCallFrame(
643             inlineCallFrame)->argumentsRegister().offset() + inlineCallFrame->stackOffset);
644     }
645     
646     VirtualRegister baselineArgumentsRegisterFor(const CodeOrigin& codeOrigin)
647     {
648         return baselineArgumentsRegisterFor(codeOrigin.inlineCallFrame);
649     }
650     
651     SymbolTable* symbolTableFor(const CodeOrigin& codeOrigin)
652     {
653         return baselineCodeBlockFor(codeOrigin)->symbolTable();
654     }
655
656     int offsetOfLocals(const CodeOrigin& codeOrigin)
657     {
658         if (!codeOrigin.inlineCallFrame)
659             return 0;
660         return codeOrigin.inlineCallFrame->stackOffset * sizeof(Register);
661     }
662
663     int offsetOfArguments(InlineCallFrame* inlineCallFrame)
664     {
665         if (!inlineCallFrame)
666             return CallFrame::argumentOffset(0) * sizeof(Register);
667         if (inlineCallFrame->arguments.size() <= 1)
668             return 0;
669         ValueRecovery recovery = inlineCallFrame->arguments[1];
670         RELEASE_ASSERT(recovery.technique() == DisplacedInJSStack);
671         return recovery.virtualRegister().offset() * sizeof(Register);
672     }
673     
674     int offsetOfArguments(const CodeOrigin& codeOrigin)
675     {
676         return offsetOfArguments(codeOrigin.inlineCallFrame);
677     }
678     
679     void emitLoadStructure(RegisterID source, RegisterID dest, RegisterID scratch)
680     {
681 #if USE(JSVALUE64)
682         load32(MacroAssembler::Address(source, JSCell::structureIDOffset()), dest);
683         loadPtr(vm()->heap.structureIDTable().base(), scratch);
684         loadPtr(MacroAssembler::BaseIndex(scratch, dest, MacroAssembler::TimesEight), dest);
685 #else
686         UNUSED_PARAM(scratch);
687         loadPtr(MacroAssembler::Address(source, JSCell::structureIDOffset()), dest);
688 #endif
689     }
690
691     static void emitLoadStructure(AssemblyHelpers& jit, RegisterID base, RegisterID dest, RegisterID scratch)
692     {
693 #if USE(JSVALUE64)
694         jit.load32(MacroAssembler::Address(base, JSCell::structureIDOffset()), dest);
695         jit.loadPtr(jit.vm()->heap.structureIDTable().base(), scratch);
696         jit.loadPtr(MacroAssembler::BaseIndex(scratch, dest, MacroAssembler::TimesEight), dest);
697 #else
698         UNUSED_PARAM(scratch);
699         jit.loadPtr(MacroAssembler::Address(base, JSCell::structureIDOffset()), dest);
700 #endif
701     }
702
703     void emitStoreStructureWithTypeInfo(TrustedImmPtr structure, RegisterID dest, RegisterID)
704     {
705         emitStoreStructureWithTypeInfo(*this, structure, dest);
706     }
707
708     void emitStoreStructureWithTypeInfo(RegisterID structure, RegisterID dest, RegisterID scratch)
709     {
710 #if USE(JSVALUE64)
711         load64(MacroAssembler::Address(structure, Structure::structureIDOffset()), scratch);
712         store64(scratch, MacroAssembler::Address(dest, JSCell::structureIDOffset()));
713 #else
714         // Store all the info flags using a single 32-bit wide load and store.
715         load32(MacroAssembler::Address(structure, Structure::indexingTypeOffset()), scratch);
716         store32(scratch, MacroAssembler::Address(dest, JSCell::indexingTypeOffset()));
717
718         // Store the StructureID
719         storePtr(structure, MacroAssembler::Address(dest, JSCell::structureIDOffset()));
720 #endif
721     }
722
723     static void emitStoreStructureWithTypeInfo(AssemblyHelpers& jit, TrustedImmPtr structure, RegisterID dest);
724
725     Jump jumpIfIsRememberedOrInEden(GPRReg cell)
726     {
727         return branchTest8(MacroAssembler::NonZero, MacroAssembler::Address(cell, JSCell::gcDataOffset()));
728     }
729
730     Jump jumpIfIsRememberedOrInEden(JSCell* cell)
731     {
732         uint8_t* address = reinterpret_cast<uint8_t*>(cell) + JSCell::gcDataOffset();
733         return branchTest8(MacroAssembler::NonZero, MacroAssembler::AbsoluteAddress(address));
734     }
735
736     Vector<BytecodeAndMachineOffset>& decodedCodeMapFor(CodeBlock*);
737     
738 protected:
739     VM* m_vm;
740     CodeBlock* m_codeBlock;
741     CodeBlock* m_baselineCodeBlock;
742
743     HashMap<CodeBlock*, Vector<BytecodeAndMachineOffset>> m_decodedCodeMaps;
744 };
745
746 } // namespace JSC
747
748 #endif // ENABLE(JIT)
749
750 #endif // AssemblyHelpers_h
751