Unreviewed, rolling out r202413.
[WebKit.git] / Source / JavaScriptCore / jit / AssemblyHelpers.h
1 /*
2  * Copyright (C) 2011, 2013-2016 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #ifndef AssemblyHelpers_h
27 #define AssemblyHelpers_h
28
29 #if ENABLE(JIT)
30
31 #include "CodeBlock.h"
32 #include "CopyBarrier.h"
33 #include "FPRInfo.h"
34 #include "GPRInfo.h"
35 #include "InlineCallFrame.h"
36 #include "JITCode.h"
37 #include "MacroAssembler.h"
38 #include "MaxFrameExtentForSlowPathCall.h"
39 #include "RegisterAtOffsetList.h"
40 #include "RegisterSet.h"
41 #include "SuperSampler.h"
42 #include "TypeofType.h"
43 #include "VM.h"
44
45 namespace JSC {
46
47 typedef void (*V_DebugOperation_EPP)(ExecState*, void*, void*);
48
49 class AssemblyHelpers : public MacroAssembler {
50 public:
51     AssemblyHelpers(VM* vm, CodeBlock* codeBlock)
52         : m_vm(vm)
53         , m_codeBlock(codeBlock)
54         , m_baselineCodeBlock(codeBlock ? codeBlock->baselineAlternative() : 0)
55     {
56         if (m_codeBlock) {
57             ASSERT(m_baselineCodeBlock);
58             ASSERT(!m_baselineCodeBlock->alternative());
59             ASSERT(m_baselineCodeBlock->jitType() == JITCode::None || JITCode::isBaselineCode(m_baselineCodeBlock->jitType()));
60         }
61     }
62     
63     CodeBlock* codeBlock() { return m_codeBlock; }
64     VM* vm() { return m_vm; }
65     AssemblerType_T& assembler() { return m_assembler; }
66
67     void checkStackPointerAlignment()
68     {
69         // This check is both unneeded and harder to write correctly for ARM64
70 #if !defined(NDEBUG) && !CPU(ARM64)
71         Jump stackPointerAligned = branchTestPtr(Zero, stackPointerRegister, TrustedImm32(0xf));
72         abortWithReason(AHStackPointerMisaligned);
73         stackPointerAligned.link(this);
74 #endif
75     }
76     
77     template<typename T>
78     void storeCell(T cell, Address address)
79     {
80 #if USE(JSVALUE64)
81         store64(cell, address);
82 #else
83         store32(cell, address.withOffset(PayloadOffset));
84         store32(TrustedImm32(JSValue::CellTag), address.withOffset(TagOffset));
85 #endif
86     }
87     
88     void loadCell(Address address, GPRReg gpr)
89     {
90 #if USE(JSVALUE64)
91         load64(address, gpr);
92 #else
93         load32(address.withOffset(PayloadOffset), gpr);
94 #endif
95     }
96     
97     void storeValue(JSValueRegs regs, Address address)
98     {
99 #if USE(JSVALUE64)
100         store64(regs.gpr(), address);
101 #else
102         store32(regs.payloadGPR(), address.withOffset(PayloadOffset));
103         store32(regs.tagGPR(), address.withOffset(TagOffset));
104 #endif
105     }
106     
107     void storeValue(JSValueRegs regs, BaseIndex address)
108     {
109 #if USE(JSVALUE64)
110         store64(regs.gpr(), address);
111 #else
112         store32(regs.payloadGPR(), address.withOffset(PayloadOffset));
113         store32(regs.tagGPR(), address.withOffset(TagOffset));
114 #endif
115     }
116     
117     void storeValue(JSValueRegs regs, void* address)
118     {
119 #if USE(JSVALUE64)
120         store64(regs.gpr(), address);
121 #else
122         store32(regs.payloadGPR(), bitwise_cast<void*>(bitwise_cast<uintptr_t>(address) + PayloadOffset));
123         store32(regs.tagGPR(), bitwise_cast<void*>(bitwise_cast<uintptr_t>(address) + TagOffset));
124 #endif
125     }
126     
127     void loadValue(Address address, JSValueRegs regs)
128     {
129 #if USE(JSVALUE64)
130         load64(address, regs.gpr());
131 #else
132         if (address.base == regs.payloadGPR()) {
133             load32(address.withOffset(TagOffset), regs.tagGPR());
134             load32(address.withOffset(PayloadOffset), regs.payloadGPR());
135         } else {
136             load32(address.withOffset(PayloadOffset), regs.payloadGPR());
137             load32(address.withOffset(TagOffset), regs.tagGPR());
138         }
139 #endif
140     }
141     
142     void loadValue(BaseIndex address, JSValueRegs regs)
143     {
144 #if USE(JSVALUE64)
145         load64(address, regs.gpr());
146 #else
147         if (address.base == regs.payloadGPR() || address.index == regs.payloadGPR()) {
148             // We actually could handle the case where the registers are aliased to both
149             // tag and payload, but we don't for now.
150             RELEASE_ASSERT(address.base != regs.tagGPR());
151             RELEASE_ASSERT(address.index != regs.tagGPR());
152             
153             load32(address.withOffset(TagOffset), regs.tagGPR());
154             load32(address.withOffset(PayloadOffset), regs.payloadGPR());
155         } else {
156             load32(address.withOffset(PayloadOffset), regs.payloadGPR());
157             load32(address.withOffset(TagOffset), regs.tagGPR());
158         }
159 #endif
160     }
161     
162     // Note that this clobbers offset.
163     void loadProperty(GPRReg object, GPRReg offset, JSValueRegs result);
164
165     void moveValueRegs(JSValueRegs srcRegs, JSValueRegs destRegs)
166     {
167 #if USE(JSVALUE32_64)
168         move(srcRegs.tagGPR(), destRegs.tagGPR());
169 #endif
170         move(srcRegs.payloadGPR(), destRegs.payloadGPR());
171     }
172
173     void moveValue(JSValue value, JSValueRegs regs)
174     {
175 #if USE(JSVALUE64)
176         move(Imm64(JSValue::encode(value)), regs.gpr());
177 #else
178         move(Imm32(value.tag()), regs.tagGPR());
179         move(Imm32(value.payload()), regs.payloadGPR());
180 #endif
181     }
182
183     void moveTrustedValue(JSValue value, JSValueRegs regs)
184     {
185 #if USE(JSVALUE64)
186         move(TrustedImm64(JSValue::encode(value)), regs.gpr());
187 #else
188         move(TrustedImm32(value.tag()), regs.tagGPR());
189         move(TrustedImm32(value.payload()), regs.payloadGPR());
190 #endif
191     }
192     
193     void storeTrustedValue(JSValue value, Address address)
194     {
195 #if USE(JSVALUE64)
196         store64(TrustedImm64(JSValue::encode(value)), address);
197 #else
198         store32(TrustedImm32(value.tag()), address.withOffset(TagOffset));
199         store32(TrustedImm32(value.payload()), address.withOffset(PayloadOffset));
200 #endif
201     }
202
203     void storeTrustedValue(JSValue value, BaseIndex address)
204     {
205 #if USE(JSVALUE64)
206         store64(TrustedImm64(JSValue::encode(value)), address);
207 #else
208         store32(TrustedImm32(value.tag()), address.withOffset(TagOffset));
209         store32(TrustedImm32(value.payload()), address.withOffset(PayloadOffset));
210 #endif
211     }
212
213     void emitSaveCalleeSavesFor(CodeBlock* codeBlock)
214     {
215         ASSERT(codeBlock);
216
217         RegisterAtOffsetList* calleeSaves = codeBlock->calleeSaveRegisters();
218         RegisterSet dontSaveRegisters = RegisterSet(RegisterSet::stackRegisters(), RegisterSet::allFPRs());
219         unsigned registerCount = calleeSaves->size();
220
221         for (unsigned i = 0; i < registerCount; i++) {
222             RegisterAtOffset entry = calleeSaves->at(i);
223             if (dontSaveRegisters.get(entry.reg()))
224                 continue;
225             storePtr(entry.reg().gpr(), Address(framePointerRegister, entry.offset()));
226         }
227     }
228     
229     enum RestoreTagRegisterMode { UseExistingTagRegisterContents, CopyBaselineCalleeSavedRegistersFromBaseFrame };
230
231     void emitSaveOrCopyCalleeSavesFor(CodeBlock* codeBlock, VirtualRegister offsetVirtualRegister, RestoreTagRegisterMode tagRegisterMode, GPRReg temp)
232     {
233         ASSERT(codeBlock);
234         
235         RegisterAtOffsetList* calleeSaves = codeBlock->calleeSaveRegisters();
236         RegisterSet dontSaveRegisters = RegisterSet(RegisterSet::stackRegisters(), RegisterSet::allFPRs());
237         unsigned registerCount = calleeSaves->size();
238
239 #if USE(JSVALUE64)
240         RegisterSet baselineCalleeSaves = RegisterSet::llintBaselineCalleeSaveRegisters();
241 #endif
242         
243         for (unsigned i = 0; i < registerCount; i++) {
244             RegisterAtOffset entry = calleeSaves->at(i);
245             if (dontSaveRegisters.get(entry.reg()))
246                 continue;
247             
248             GPRReg registerToWrite;
249             
250 #if USE(JSVALUE32_64)
251             UNUSED_PARAM(tagRegisterMode);
252             UNUSED_PARAM(temp);
253 #else
254             if (tagRegisterMode == CopyBaselineCalleeSavedRegistersFromBaseFrame && baselineCalleeSaves.get(entry.reg())) {
255                 registerToWrite = temp;
256                 loadPtr(AssemblyHelpers::Address(GPRInfo::callFrameRegister, entry.offset()), registerToWrite);
257             } else
258 #endif
259                 registerToWrite = entry.reg().gpr();
260
261             storePtr(registerToWrite, Address(framePointerRegister, offsetVirtualRegister.offsetInBytes() + entry.offset()));
262         }
263     }
264     
265     void emitRestoreCalleeSavesFor(CodeBlock* codeBlock)
266     {
267         ASSERT(codeBlock);
268
269         RegisterAtOffsetList* calleeSaves = codeBlock->calleeSaveRegisters();
270         RegisterSet dontRestoreRegisters = RegisterSet(RegisterSet::stackRegisters(), RegisterSet::allFPRs());
271         unsigned registerCount = calleeSaves->size();
272         
273         for (unsigned i = 0; i < registerCount; i++) {
274             RegisterAtOffset entry = calleeSaves->at(i);
275             if (dontRestoreRegisters.get(entry.reg()))
276                 continue;
277             loadPtr(Address(framePointerRegister, entry.offset()), entry.reg().gpr());
278         }
279     }
280
281     void emitSaveCalleeSaves()
282     {
283         emitSaveCalleeSavesFor(codeBlock());
284     }
285
286     void emitSaveThenMaterializeTagRegisters()
287     {
288 #if USE(JSVALUE64)
289 #if CPU(ARM64)
290         pushPair(GPRInfo::tagTypeNumberRegister, GPRInfo::tagMaskRegister);
291 #else
292         push(GPRInfo::tagTypeNumberRegister);
293         push(GPRInfo::tagMaskRegister);
294 #endif
295         emitMaterializeTagCheckRegisters();
296 #endif
297     }
298     
299     void emitRestoreCalleeSaves()
300     {
301         emitRestoreCalleeSavesFor(codeBlock());
302     }
303
304     void emitRestoreSavedTagRegisters()
305     {
306 #if USE(JSVALUE64)
307 #if CPU(ARM64)
308         popPair(GPRInfo::tagTypeNumberRegister, GPRInfo::tagMaskRegister);
309 #else
310         pop(GPRInfo::tagMaskRegister);
311         pop(GPRInfo::tagTypeNumberRegister);
312 #endif
313 #endif
314     }
315
316     void copyCalleeSavesToVMEntryFrameCalleeSavesBuffer(const TempRegisterSet& usedRegisters = { RegisterSet::stubUnavailableRegisters() })
317     {
318 #if NUMBER_OF_CALLEE_SAVES_REGISTERS > 0
319         GPRReg temp1 = usedRegisters.getFreeGPR(0);
320
321         loadPtr(&m_vm->topVMEntryFrame, temp1);
322         addPtr(TrustedImm32(VMEntryFrame::calleeSaveRegistersBufferOffset()), temp1);
323
324         RegisterAtOffsetList* allCalleeSaves = m_vm->getAllCalleeSaveRegisterOffsets();
325         RegisterSet dontCopyRegisters = RegisterSet::stackRegisters();
326         unsigned registerCount = allCalleeSaves->size();
327         
328         for (unsigned i = 0; i < registerCount; i++) {
329             RegisterAtOffset entry = allCalleeSaves->at(i);
330             if (dontCopyRegisters.get(entry.reg()))
331                 continue;
332             if (entry.reg().isGPR())
333                 storePtr(entry.reg().gpr(), Address(temp1, entry.offset()));
334             else
335                 storeDouble(entry.reg().fpr(), Address(temp1, entry.offset()));
336         }
337 #else
338         UNUSED_PARAM(usedRegisters);
339 #endif
340     }
341
342     void restoreCalleeSavesFromVMEntryFrameCalleeSavesBuffer();
343
344     void copyCalleeSavesFromFrameOrRegisterToVMEntryFrameCalleeSavesBuffer(const TempRegisterSet& usedRegisters = { RegisterSet::stubUnavailableRegisters() })
345     {
346 #if NUMBER_OF_CALLEE_SAVES_REGISTERS > 0
347         GPRReg temp1 = usedRegisters.getFreeGPR(0);
348         GPRReg temp2 = usedRegisters.getFreeGPR(1);
349         FPRReg fpTemp = usedRegisters.getFreeFPR();
350         ASSERT(temp2 != InvalidGPRReg);
351
352         ASSERT(codeBlock());
353
354         // Copy saved calleeSaves on stack or unsaved calleeSaves in register to vm calleeSave buffer
355         loadPtr(&m_vm->topVMEntryFrame, temp1);
356         addPtr(TrustedImm32(VMEntryFrame::calleeSaveRegistersBufferOffset()), temp1);
357
358         RegisterAtOffsetList* allCalleeSaves = m_vm->getAllCalleeSaveRegisterOffsets();
359         RegisterAtOffsetList* currentCalleeSaves = codeBlock()->calleeSaveRegisters();
360         RegisterSet dontCopyRegisters = RegisterSet::stackRegisters();
361         unsigned registerCount = allCalleeSaves->size();
362
363         for (unsigned i = 0; i < registerCount; i++) {
364             RegisterAtOffset vmEntry = allCalleeSaves->at(i);
365             if (dontCopyRegisters.get(vmEntry.reg()))
366                 continue;
367             RegisterAtOffset* currentFrameEntry = currentCalleeSaves->find(vmEntry.reg());
368
369             if (vmEntry.reg().isGPR()) {
370                 GPRReg regToStore;
371                 if (currentFrameEntry) {
372                     // Load calleeSave from stack into temp register
373                     regToStore = temp2;
374                     loadPtr(Address(framePointerRegister, currentFrameEntry->offset()), regToStore);
375                 } else
376                     // Just store callee save directly
377                     regToStore = vmEntry.reg().gpr();
378
379                 storePtr(regToStore, Address(temp1, vmEntry.offset()));
380             } else {
381                 FPRReg fpRegToStore;
382                 if (currentFrameEntry) {
383                     // Load calleeSave from stack into temp register
384                     fpRegToStore = fpTemp;
385                     loadDouble(Address(framePointerRegister, currentFrameEntry->offset()), fpRegToStore);
386                 } else
387                     // Just store callee save directly
388                     fpRegToStore = vmEntry.reg().fpr();
389
390                 storeDouble(fpRegToStore, Address(temp1, vmEntry.offset()));
391             }
392         }
393 #else
394         UNUSED_PARAM(usedRegisters);
395 #endif
396     }
397
398     void emitMaterializeTagCheckRegisters()
399     {
400 #if USE(JSVALUE64)
401         move(MacroAssembler::TrustedImm64(TagTypeNumber), GPRInfo::tagTypeNumberRegister);
402         orPtr(MacroAssembler::TrustedImm32(TagBitTypeOther), GPRInfo::tagTypeNumberRegister, GPRInfo::tagMaskRegister);
403 #endif
404     }
405
406 #if CPU(X86_64) || CPU(X86)
407     static size_t prologueStackPointerDelta()
408     {
409         // Prologue only saves the framePointerRegister
410         return sizeof(void*);
411     }
412
413     void emitFunctionPrologue()
414     {
415         push(framePointerRegister);
416         move(stackPointerRegister, framePointerRegister);
417     }
418
419     void emitFunctionEpilogueWithEmptyFrame()
420     {
421         pop(framePointerRegister);
422     }
423
424     void emitFunctionEpilogue()
425     {
426         move(framePointerRegister, stackPointerRegister);
427         pop(framePointerRegister);
428     }
429
430     void preserveReturnAddressAfterCall(GPRReg reg)
431     {
432         pop(reg);
433     }
434
435     void restoreReturnAddressBeforeReturn(GPRReg reg)
436     {
437         push(reg);
438     }
439
440     void restoreReturnAddressBeforeReturn(Address address)
441     {
442         push(address);
443     }
444 #endif // CPU(X86_64) || CPU(X86)
445
446 #if CPU(ARM) || CPU(ARM64)
447     static size_t prologueStackPointerDelta()
448     {
449         // Prologue saves the framePointerRegister and linkRegister
450         return 2 * sizeof(void*);
451     }
452
453     void emitFunctionPrologue()
454     {
455         pushPair(framePointerRegister, linkRegister);
456         move(stackPointerRegister, framePointerRegister);
457     }
458
459     void emitFunctionEpilogueWithEmptyFrame()
460     {
461         popPair(framePointerRegister, linkRegister);
462     }
463
464     void emitFunctionEpilogue()
465     {
466         move(framePointerRegister, stackPointerRegister);
467         emitFunctionEpilogueWithEmptyFrame();
468     }
469
470     ALWAYS_INLINE void preserveReturnAddressAfterCall(RegisterID reg)
471     {
472         move(linkRegister, reg);
473     }
474
475     ALWAYS_INLINE void restoreReturnAddressBeforeReturn(RegisterID reg)
476     {
477         move(reg, linkRegister);
478     }
479
480     ALWAYS_INLINE void restoreReturnAddressBeforeReturn(Address address)
481     {
482         loadPtr(address, linkRegister);
483     }
484 #endif
485
486 #if CPU(MIPS)
487     static size_t prologueStackPointerDelta()
488     {
489         // Prologue saves the framePointerRegister and returnAddressRegister
490         return 2 * sizeof(void*);
491     }
492
493     void emitFunctionPrologue()
494     {
495         pushPair(framePointerRegister, returnAddressRegister);
496         move(stackPointerRegister, framePointerRegister);
497     }
498
499     void emitFunctionEpilogueWithEmptyFrame()
500     {
501         popPair(framePointerRegister, returnAddressRegister);
502     }
503
504     void emitFunctionEpilogue()
505     {
506         move(framePointerRegister, stackPointerRegister);
507         emitFunctionEpilogueWithEmptyFrame();
508     }
509
510     ALWAYS_INLINE void preserveReturnAddressAfterCall(RegisterID reg)
511     {
512         move(returnAddressRegister, reg);
513     }
514
515     ALWAYS_INLINE void restoreReturnAddressBeforeReturn(RegisterID reg)
516     {
517         move(reg, returnAddressRegister);
518     }
519
520     ALWAYS_INLINE void restoreReturnAddressBeforeReturn(Address address)
521     {
522         loadPtr(address, returnAddressRegister);
523     }
524 #endif
525
526 #if CPU(SH4)
527     static size_t prologueStackPointerDelta()
528     {
529         // Prologue saves the framePointerRegister and link register
530         return 2 * sizeof(void*);
531     }
532
533     void emitFunctionPrologue()
534     {
535         push(linkRegister);
536         push(framePointerRegister);
537         move(stackPointerRegister, framePointerRegister);
538     }
539
540     void emitFunctionEpilogue()
541     {
542         move(framePointerRegister, stackPointerRegister);
543         pop(framePointerRegister);
544         pop(linkRegister);
545     }
546
547     ALWAYS_INLINE void preserveReturnAddressAfterCall(RegisterID reg)
548     {
549         m_assembler.stspr(reg);
550     }
551
552     ALWAYS_INLINE void restoreReturnAddressBeforeReturn(RegisterID reg)
553     {
554         m_assembler.ldspr(reg);
555     }
556
557     ALWAYS_INLINE void restoreReturnAddressBeforeReturn(Address address)
558     {
559         loadPtrLinkReg(address);
560     }
561 #endif
562
563     void emitGetFromCallFrameHeaderPtr(JSStack::CallFrameHeaderEntry entry, GPRReg to, GPRReg from = GPRInfo::callFrameRegister)
564     {
565         loadPtr(Address(from, entry * sizeof(Register)), to);
566     }
567     void emitGetFromCallFrameHeader32(JSStack::CallFrameHeaderEntry entry, GPRReg to, GPRReg from = GPRInfo::callFrameRegister)
568     {
569         load32(Address(from, entry * sizeof(Register)), to);
570     }
571 #if USE(JSVALUE64)
572     void emitGetFromCallFrameHeader64(JSStack::CallFrameHeaderEntry entry, GPRReg to, GPRReg from = GPRInfo::callFrameRegister)
573     {
574         load64(Address(from, entry * sizeof(Register)), to);
575     }
576 #endif // USE(JSVALUE64)
577     void emitPutToCallFrameHeader(GPRReg from, JSStack::CallFrameHeaderEntry entry)
578     {
579         storePtr(from, Address(GPRInfo::callFrameRegister, entry * sizeof(Register)));
580     }
581
582     void emitPutToCallFrameHeader(void* value, JSStack::CallFrameHeaderEntry entry)
583     {
584         storePtr(TrustedImmPtr(value), Address(GPRInfo::callFrameRegister, entry * sizeof(Register)));
585     }
586
587     void emitGetCallerFrameFromCallFrameHeaderPtr(RegisterID to)
588     {
589         loadPtr(Address(GPRInfo::callFrameRegister, CallFrame::callerFrameOffset()), to);
590     }
591     void emitPutCallerFrameToCallFrameHeader(RegisterID from)
592     {
593         storePtr(from, Address(GPRInfo::callFrameRegister, CallFrame::callerFrameOffset()));
594     }
595
596     void emitPutReturnPCToCallFrameHeader(RegisterID from)
597     {
598         storePtr(from, Address(GPRInfo::callFrameRegister, CallFrame::returnPCOffset()));
599     }
600     void emitPutReturnPCToCallFrameHeader(TrustedImmPtr from)
601     {
602         storePtr(from, Address(GPRInfo::callFrameRegister, CallFrame::returnPCOffset()));
603     }
604
605     // emitPutToCallFrameHeaderBeforePrologue() and related are used to access callee frame header
606     // fields before the code from emitFunctionPrologue() has executed.
607     // First, the access is via the stack pointer. Second, the address calculation must also take
608     // into account that the stack pointer may not have been adjusted down for the return PC and/or
609     // caller's frame pointer. On some platforms, the callee is responsible for pushing the
610     // "link register" containing the return address in the function prologue.
611 #if USE(JSVALUE64)
612     void emitPutToCallFrameHeaderBeforePrologue(GPRReg from, JSStack::CallFrameHeaderEntry entry)
613     {
614         storePtr(from, Address(stackPointerRegister, entry * static_cast<ptrdiff_t>(sizeof(Register)) - prologueStackPointerDelta()));
615     }
616 #else
617     void emitPutPayloadToCallFrameHeaderBeforePrologue(GPRReg from, JSStack::CallFrameHeaderEntry entry)
618     {
619         storePtr(from, Address(stackPointerRegister, entry * static_cast<ptrdiff_t>(sizeof(Register)) - prologueStackPointerDelta() + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
620     }
621
622     void emitPutTagToCallFrameHeaderBeforePrologue(TrustedImm32 tag, JSStack::CallFrameHeaderEntry entry)
623     {
624         storePtr(tag, Address(stackPointerRegister, entry * static_cast<ptrdiff_t>(sizeof(Register)) - prologueStackPointerDelta() + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
625     }
626 #endif
627     
628     JumpList branchIfNotEqual(JSValueRegs regs, JSValue value)
629     {
630 #if USE(JSVALUE64)
631         return branch64(NotEqual, regs.gpr(), TrustedImm64(JSValue::encode(value)));
632 #else
633         JumpList result;
634         result.append(branch32(NotEqual, regs.tagGPR(), TrustedImm32(value.tag())));
635         if (value.isEmpty() || value.isUndefinedOrNull())
636             return result; // These don't have anything interesting in the payload.
637         result.append(branch32(NotEqual, regs.payloadGPR(), TrustedImm32(value.payload())));
638         return result;
639 #endif
640     }
641     
642     Jump branchIfEqual(JSValueRegs regs, JSValue value)
643     {
644 #if USE(JSVALUE64)
645         return branch64(Equal, regs.gpr(), TrustedImm64(JSValue::encode(value)));
646 #else
647         Jump notEqual;
648         // These don't have anything interesting in the payload.
649         if (!value.isEmpty() && !value.isUndefinedOrNull())
650             notEqual = branch32(NotEqual, regs.payloadGPR(), TrustedImm32(value.payload()));
651         Jump result = branch32(Equal, regs.tagGPR(), TrustedImm32(value.tag()));
652         if (notEqual.isSet())
653             notEqual.link(this);
654         return result;
655 #endif
656     }
657
658     Jump branchIfNotCell(GPRReg reg, TagRegistersMode mode = HaveTagRegisters)
659     {
660 #if USE(JSVALUE64)
661         if (mode == HaveTagRegisters)
662             return branchTest64(NonZero, reg, GPRInfo::tagMaskRegister);
663         return branchTest64(NonZero, reg, TrustedImm64(TagMask));
664 #else
665         UNUSED_PARAM(mode);
666         return branch32(MacroAssembler::NotEqual, reg, TrustedImm32(JSValue::CellTag));
667 #endif
668     }
669     Jump branchIfNotCell(JSValueRegs regs, TagRegistersMode mode = HaveTagRegisters)
670     {
671 #if USE(JSVALUE64)
672         return branchIfNotCell(regs.gpr(), mode);
673 #else
674         return branchIfNotCell(regs.tagGPR(), mode);
675 #endif
676     }
677     
678     Jump branchIfCell(GPRReg reg, TagRegistersMode mode = HaveTagRegisters)
679     {
680 #if USE(JSVALUE64)
681         if (mode == HaveTagRegisters)
682             return branchTest64(Zero, reg, GPRInfo::tagMaskRegister);
683         return branchTest64(Zero, reg, TrustedImm64(TagMask));
684 #else
685         UNUSED_PARAM(mode);
686         return branch32(MacroAssembler::Equal, reg, TrustedImm32(JSValue::CellTag));
687 #endif
688     }
689     Jump branchIfCell(JSValueRegs regs, TagRegistersMode mode = HaveTagRegisters)
690     {
691 #if USE(JSVALUE64)
692         return branchIfCell(regs.gpr(), mode);
693 #else
694         return branchIfCell(regs.tagGPR(), mode);
695 #endif
696     }
697     
698     Jump branchIfOther(JSValueRegs regs, GPRReg tempGPR)
699     {
700 #if USE(JSVALUE64)
701         move(regs.gpr(), tempGPR);
702         and64(TrustedImm32(~TagBitUndefined), tempGPR);
703         return branch64(Equal, tempGPR, TrustedImm64(ValueNull));
704 #else
705         or32(TrustedImm32(1), regs.tagGPR(), tempGPR);
706         return branch32(Equal, tempGPR, TrustedImm32(JSValue::NullTag));
707 #endif
708     }
709     
710     Jump branchIfNotOther(JSValueRegs regs, GPRReg tempGPR)
711     {
712 #if USE(JSVALUE64)
713         move(regs.gpr(), tempGPR);
714         and64(TrustedImm32(~TagBitUndefined), tempGPR);
715         return branch64(NotEqual, tempGPR, TrustedImm64(ValueNull));
716 #else
717         or32(TrustedImm32(1), regs.tagGPR(), tempGPR);
718         return branch32(NotEqual, tempGPR, TrustedImm32(JSValue::NullTag));
719 #endif
720     }
721     
722     Jump branchIfInt32(JSValueRegs regs, TagRegistersMode mode = HaveTagRegisters)
723     {
724 #if USE(JSVALUE64)
725         if (mode == HaveTagRegisters)
726             return branch64(AboveOrEqual, regs.gpr(), GPRInfo::tagTypeNumberRegister);
727         return branch64(AboveOrEqual, regs.gpr(), TrustedImm64(TagTypeNumber));
728 #else
729         UNUSED_PARAM(mode);
730         return branch32(Equal, regs.tagGPR(), TrustedImm32(JSValue::Int32Tag));
731 #endif
732     }
733
734 #if USE(JSVALUE64)
735     Jump branchIfNotInt32(GPRReg gpr, TagRegistersMode mode = HaveTagRegisters)
736     {
737         if (mode == HaveTagRegisters)
738             return branch64(Below, gpr, GPRInfo::tagTypeNumberRegister);
739         return branch64(Below, gpr, TrustedImm64(TagTypeNumber));
740     }
741 #endif
742
743     Jump branchIfNotInt32(JSValueRegs regs, TagRegistersMode mode = HaveTagRegisters)
744     {
745 #if USE(JSVALUE64)
746         return branchIfNotInt32(regs.gpr(), mode);
747 #else
748         UNUSED_PARAM(mode);
749         return branch32(NotEqual, regs.tagGPR(), TrustedImm32(JSValue::Int32Tag));
750 #endif
751     }
752
753     // Note that the tempGPR is not used in 64-bit mode.
754     Jump branchIfNumber(JSValueRegs regs, GPRReg tempGPR, TagRegistersMode mode = HaveTagRegisters)
755     {
756 #if USE(JSVALUE64)
757         UNUSED_PARAM(tempGPR);
758         if (mode == HaveTagRegisters)
759             return branchTest64(NonZero, regs.gpr(), GPRInfo::tagTypeNumberRegister);
760         return branchTest64(NonZero, regs.gpr(), TrustedImm64(TagTypeNumber));
761 #else
762         UNUSED_PARAM(mode);
763         add32(TrustedImm32(1), regs.tagGPR(), tempGPR);
764         return branch32(Below, tempGPR, TrustedImm32(JSValue::LowestTag + 1));
765 #endif
766     }
767     
768     // Note that the tempGPR is not used in 64-bit mode.
769     Jump branchIfNotNumber(JSValueRegs regs, GPRReg tempGPR, TagRegistersMode mode = HaveTagRegisters)
770     {
771 #if USE(JSVALUE64)
772         UNUSED_PARAM(tempGPR);
773         if (mode == HaveTagRegisters)
774             return branchTest64(Zero, regs.gpr(), GPRInfo::tagTypeNumberRegister);
775         return branchTest64(Zero, regs.gpr(), TrustedImm64(TagTypeNumber));
776 #else
777         UNUSED_PARAM(mode);
778         add32(TrustedImm32(1), regs.tagGPR(), tempGPR);
779         return branch32(AboveOrEqual, tempGPR, TrustedImm32(JSValue::LowestTag + 1));
780 #endif
781     }
782
783     Jump branchIfNotDoubleKnownNotInt32(JSValueRegs regs, TagRegistersMode mode = HaveTagRegisters)
784     {
785 #if USE(JSVALUE64)
786         if (mode == HaveTagRegisters)
787             return branchTest64(Zero, regs.gpr(), GPRInfo::tagTypeNumberRegister);
788         return branchTest64(Zero, regs.gpr(), TrustedImm64(TagTypeNumber));
789 #else
790         UNUSED_PARAM(mode);
791         return branch32(AboveOrEqual, regs.tagGPR(), TrustedImm32(JSValue::LowestTag));
792 #endif
793     }
794
795     // Note that the tempGPR is not used in 32-bit mode.
796     Jump branchIfBoolean(JSValueRegs regs, GPRReg tempGPR)
797     {
798 #if USE(JSVALUE64)
799         move(regs.gpr(), tempGPR);
800         xor64(TrustedImm32(static_cast<int32_t>(ValueFalse)), tempGPR);
801         return branchTest64(Zero, tempGPR, TrustedImm32(static_cast<int32_t>(~1)));
802 #else
803         UNUSED_PARAM(tempGPR);
804         return branch32(Equal, regs.tagGPR(), TrustedImm32(JSValue::BooleanTag));
805 #endif
806     }
807     
808     // Note that the tempGPR is not used in 32-bit mode.
809     Jump branchIfNotBoolean(JSValueRegs regs, GPRReg tempGPR)
810     {
811 #if USE(JSVALUE64)
812         move(regs.gpr(), tempGPR);
813         xor64(TrustedImm32(static_cast<int32_t>(ValueFalse)), tempGPR);
814         return branchTest64(NonZero, tempGPR, TrustedImm32(static_cast<int32_t>(~1)));
815 #else
816         UNUSED_PARAM(tempGPR);
817         return branch32(NotEqual, regs.tagGPR(), TrustedImm32(JSValue::BooleanTag));
818 #endif
819     }
820     
821     Jump branchIfObject(GPRReg cellGPR)
822     {
823         return branch8(
824             AboveOrEqual, Address(cellGPR, JSCell::typeInfoTypeOffset()), TrustedImm32(ObjectType));
825     }
826     
827     Jump branchIfNotObject(GPRReg cellGPR)
828     {
829         return branch8(
830             Below, Address(cellGPR, JSCell::typeInfoTypeOffset()), TrustedImm32(ObjectType));
831     }
832     
833     Jump branchIfType(GPRReg cellGPR, JSType type)
834     {
835         return branch8(Equal, Address(cellGPR, JSCell::typeInfoTypeOffset()), TrustedImm32(type));
836     }
837     
838     Jump branchIfNotType(GPRReg cellGPR, JSType type)
839     {
840         return branch8(NotEqual, Address(cellGPR, JSCell::typeInfoTypeOffset()), TrustedImm32(type));
841     }
842     
843     Jump branchIfString(GPRReg cellGPR) { return branchIfType(cellGPR, StringType); }
844     Jump branchIfNotString(GPRReg cellGPR) { return branchIfNotType(cellGPR, StringType); }
845     Jump branchIfSymbol(GPRReg cellGPR) { return branchIfType(cellGPR, SymbolType); }
846     Jump branchIfNotSymbol(GPRReg cellGPR) { return branchIfNotType(cellGPR, SymbolType); }
847     Jump branchIfFunction(GPRReg cellGPR) { return branchIfType(cellGPR, JSFunctionType); }
848     Jump branchIfNotFunction(GPRReg cellGPR) { return branchIfNotType(cellGPR, JSFunctionType); }
849     
850     Jump branchIfEmpty(JSValueRegs regs)
851     {
852 #if USE(JSVALUE64)
853         return branchTest64(Zero, regs.gpr());
854 #else
855         return branch32(Equal, regs.tagGPR(), TrustedImm32(JSValue::EmptyValueTag));
856 #endif
857     }
858
859     JumpList branchIfNotType(
860         JSValueRegs, GPRReg tempGPR, const InferredType::Descriptor&,
861         TagRegistersMode = HaveTagRegisters);
862
863     template<typename T>
864     Jump branchStructure(RelationalCondition condition, T leftHandSide, Structure* structure)
865     {
866 #if USE(JSVALUE64)
867         return branch32(condition, leftHandSide, TrustedImm32(structure->id()));
868 #else
869         return branchPtr(condition, leftHandSide, TrustedImmPtr(structure));
870 #endif
871     }
872
873     Jump branchIfFastTypedArray(GPRReg baseGPR);
874     Jump branchIfNotFastTypedArray(GPRReg baseGPR);
875
876     static Address addressForByteOffset(ptrdiff_t byteOffset)
877     {
878         return Address(GPRInfo::callFrameRegister, byteOffset);
879     }
880     static Address addressFor(VirtualRegister virtualRegister, GPRReg baseReg)
881     {
882         ASSERT(virtualRegister.isValid());
883         return Address(baseReg, virtualRegister.offset() * sizeof(Register));
884     }
885     static Address addressFor(VirtualRegister virtualRegister)
886     {
887         // NB. It's tempting on some architectures to sometimes use an offset from the stack
888         // register because for some offsets that will encode to a smaller instruction. But we
889         // cannot do this. We use this in places where the stack pointer has been moved to some
890         // unpredictable location.
891         ASSERT(virtualRegister.isValid());
892         return Address(GPRInfo::callFrameRegister, virtualRegister.offset() * sizeof(Register));
893     }
894     static Address addressFor(int operand)
895     {
896         return addressFor(static_cast<VirtualRegister>(operand));
897     }
898
899     static Address tagFor(VirtualRegister virtualRegister)
900     {
901         ASSERT(virtualRegister.isValid());
902         return Address(GPRInfo::callFrameRegister, virtualRegister.offset() * sizeof(Register) + TagOffset);
903     }
904     static Address tagFor(int operand)
905     {
906         return tagFor(static_cast<VirtualRegister>(operand));
907     }
908
909     static Address payloadFor(VirtualRegister virtualRegister)
910     {
911         ASSERT(virtualRegister.isValid());
912         return Address(GPRInfo::callFrameRegister, virtualRegister.offset() * sizeof(Register) + PayloadOffset);
913     }
914     static Address payloadFor(int operand)
915     {
916         return payloadFor(static_cast<VirtualRegister>(operand));
917     }
918
919     // Access to our fixed callee CallFrame.
920     static Address calleeFrameSlot(int slot)
921     {
922         ASSERT(slot >= JSStack::CallerFrameAndPCSize);
923         return Address(stackPointerRegister, sizeof(Register) * (slot - JSStack::CallerFrameAndPCSize));
924     }
925
926     // Access to our fixed callee CallFrame.
927     static Address calleeArgumentSlot(int argument)
928     {
929         return calleeFrameSlot(virtualRegisterForArgument(argument).offset());
930     }
931
932     static Address calleeFrameTagSlot(int slot)
933     {
934         return calleeFrameSlot(slot).withOffset(TagOffset);
935     }
936
937     static Address calleeFramePayloadSlot(int slot)
938     {
939         return calleeFrameSlot(slot).withOffset(PayloadOffset);
940     }
941
942     static Address calleeArgumentTagSlot(int argument)
943     {
944         return calleeArgumentSlot(argument).withOffset(TagOffset);
945     }
946
947     static Address calleeArgumentPayloadSlot(int argument)
948     {
949         return calleeArgumentSlot(argument).withOffset(PayloadOffset);
950     }
951
952     static Address calleeFrameCallerFrame()
953     {
954         return calleeFrameSlot(0).withOffset(CallFrame::callerFrameOffset());
955     }
956
957     static GPRReg selectScratchGPR(GPRReg preserve1 = InvalidGPRReg, GPRReg preserve2 = InvalidGPRReg, GPRReg preserve3 = InvalidGPRReg, GPRReg preserve4 = InvalidGPRReg, GPRReg preserve5 = InvalidGPRReg)
958     {
959         if (preserve1 != GPRInfo::regT0 && preserve2 != GPRInfo::regT0 && preserve3 != GPRInfo::regT0 && preserve4 != GPRInfo::regT0 && preserve5 != GPRInfo::regT0)
960             return GPRInfo::regT0;
961
962         if (preserve1 != GPRInfo::regT1 && preserve2 != GPRInfo::regT1 && preserve3 != GPRInfo::regT1 && preserve4 != GPRInfo::regT1 && preserve5 != GPRInfo::regT1)
963             return GPRInfo::regT1;
964
965         if (preserve1 != GPRInfo::regT2 && preserve2 != GPRInfo::regT2 && preserve3 != GPRInfo::regT2 && preserve4 != GPRInfo::regT2 && preserve5 != GPRInfo::regT2)
966             return GPRInfo::regT2;
967
968         if (preserve1 != GPRInfo::regT3 && preserve2 != GPRInfo::regT3 && preserve3 != GPRInfo::regT3 && preserve4 != GPRInfo::regT3 && preserve5 != GPRInfo::regT3)
969             return GPRInfo::regT3;
970
971         if (preserve1 != GPRInfo::regT4 && preserve2 != GPRInfo::regT4 && preserve3 != GPRInfo::regT4 && preserve4 != GPRInfo::regT4 && preserve5 != GPRInfo::regT4)
972             return GPRInfo::regT4;
973
974         return GPRInfo::regT5;
975     }
976
977     // Add a debug call. This call has no effect on JIT code execution state.
978     void debugCall(V_DebugOperation_EPP function, void* argument)
979     {
980         size_t scratchSize = sizeof(EncodedJSValue) * (GPRInfo::numberOfRegisters + FPRInfo::numberOfRegisters);
981         ScratchBuffer* scratchBuffer = m_vm->scratchBufferForSize(scratchSize);
982         EncodedJSValue* buffer = static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer());
983
984         for (unsigned i = 0; i < GPRInfo::numberOfRegisters; ++i) {
985 #if USE(JSVALUE64)
986             store64(GPRInfo::toRegister(i), buffer + i);
987 #else
988             store32(GPRInfo::toRegister(i), buffer + i);
989 #endif
990         }
991
992         for (unsigned i = 0; i < FPRInfo::numberOfRegisters; ++i) {
993             move(TrustedImmPtr(buffer + GPRInfo::numberOfRegisters + i), GPRInfo::regT0);
994             storeDouble(FPRInfo::toRegister(i), GPRInfo::regT0);
995         }
996
997         // Tell GC mark phase how much of the scratch buffer is active during call.
998         move(TrustedImmPtr(scratchBuffer->activeLengthPtr()), GPRInfo::regT0);
999         storePtr(TrustedImmPtr(scratchSize), GPRInfo::regT0);
1000
1001 #if CPU(X86_64) || CPU(ARM) || CPU(ARM64) || CPU(MIPS) || CPU(SH4)
1002         move(TrustedImmPtr(buffer), GPRInfo::argumentGPR2);
1003         move(TrustedImmPtr(argument), GPRInfo::argumentGPR1);
1004         move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
1005         GPRReg scratch = selectScratchGPR(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1, GPRInfo::argumentGPR2);
1006 #elif CPU(X86)
1007         poke(GPRInfo::callFrameRegister, 0);
1008         poke(TrustedImmPtr(argument), 1);
1009         poke(TrustedImmPtr(buffer), 2);
1010         GPRReg scratch = GPRInfo::regT0;
1011 #else
1012 #error "JIT not supported on this platform."
1013 #endif
1014         move(TrustedImmPtr(reinterpret_cast<void*>(function)), scratch);
1015         call(scratch);
1016
1017         move(TrustedImmPtr(scratchBuffer->activeLengthPtr()), GPRInfo::regT0);
1018         storePtr(TrustedImmPtr(0), GPRInfo::regT0);
1019
1020         for (unsigned i = 0; i < FPRInfo::numberOfRegisters; ++i) {
1021             move(TrustedImmPtr(buffer + GPRInfo::numberOfRegisters + i), GPRInfo::regT0);
1022             loadDouble(GPRInfo::regT0, FPRInfo::toRegister(i));
1023         }
1024         for (unsigned i = 0; i < GPRInfo::numberOfRegisters; ++i) {
1025 #if USE(JSVALUE64)
1026             load64(buffer + i, GPRInfo::toRegister(i));
1027 #else
1028             load32(buffer + i, GPRInfo::toRegister(i));
1029 #endif
1030         }
1031     }
1032
1033     // These methods JIT generate dynamic, debug-only checks - akin to ASSERTs.
1034 #if !ASSERT_DISABLED
1035     void jitAssertIsInt32(GPRReg);
1036     void jitAssertIsJSInt32(GPRReg);
1037     void jitAssertIsJSNumber(GPRReg);
1038     void jitAssertIsJSDouble(GPRReg);
1039     void jitAssertIsCell(GPRReg);
1040     void jitAssertHasValidCallFrame();
1041     void jitAssertIsNull(GPRReg);
1042     void jitAssertTagsInPlace();
1043     void jitAssertArgumentCountSane();
1044 #else
1045     void jitAssertIsInt32(GPRReg) { }
1046     void jitAssertIsJSInt32(GPRReg) { }
1047     void jitAssertIsJSNumber(GPRReg) { }
1048     void jitAssertIsJSDouble(GPRReg) { }
1049     void jitAssertIsCell(GPRReg) { }
1050     void jitAssertHasValidCallFrame() { }
1051     void jitAssertIsNull(GPRReg) { }
1052     void jitAssertTagsInPlace() { }
1053     void jitAssertArgumentCountSane() { }
1054 #endif
1055
1056     void jitReleaseAssertNoException();
1057
1058     void incrementSuperSamplerCount();
1059     void decrementSuperSamplerCount();
1060     
1061     void purifyNaN(FPRReg);
1062
1063     // These methods convert between doubles, and doubles boxed and JSValues.
1064 #if USE(JSVALUE64)
1065     GPRReg boxDouble(FPRReg fpr, GPRReg gpr)
1066     {
1067         moveDoubleTo64(fpr, gpr);
1068         sub64(GPRInfo::tagTypeNumberRegister, gpr);
1069         jitAssertIsJSDouble(gpr);
1070         return gpr;
1071     }
1072     FPRReg unboxDoubleWithoutAssertions(GPRReg gpr, GPRReg resultGPR, FPRReg fpr)
1073     {
1074         add64(GPRInfo::tagTypeNumberRegister, gpr, resultGPR);
1075         move64ToDouble(resultGPR, fpr);
1076         return fpr;
1077     }
1078     FPRReg unboxDouble(GPRReg gpr, GPRReg resultGPR, FPRReg fpr)
1079     {
1080         jitAssertIsJSDouble(gpr);
1081         return unboxDoubleWithoutAssertions(gpr, resultGPR, fpr);
1082     }
1083     
1084     void boxDouble(FPRReg fpr, JSValueRegs regs)
1085     {
1086         boxDouble(fpr, regs.gpr());
1087     }
1088
1089     void unboxDoubleNonDestructive(JSValueRegs regs, FPRReg destFPR, GPRReg resultGPR, FPRReg)
1090     {
1091         unboxDouble(regs.payloadGPR(), resultGPR, destFPR);
1092     }
1093
1094     // Here are possible arrangements of source, target, scratch:
1095     // - source, target, scratch can all be separate registers.
1096     // - source and target can be the same but scratch is separate.
1097     // - target and scratch can be the same but source is separate.
1098     void boxInt52(GPRReg source, GPRReg target, GPRReg scratch, FPRReg fpScratch)
1099     {
1100         // Is it an int32?
1101         signExtend32ToPtr(source, scratch);
1102         Jump isInt32 = branch64(Equal, source, scratch);
1103         
1104         // Nope, it's not, but regT0 contains the int64 value.
1105         convertInt64ToDouble(source, fpScratch);
1106         boxDouble(fpScratch, target);
1107         Jump done = jump();
1108         
1109         isInt32.link(this);
1110         zeroExtend32ToPtr(source, target);
1111         or64(GPRInfo::tagTypeNumberRegister, target);
1112         
1113         done.link(this);
1114     }
1115 #endif
1116
1117 #if USE(JSVALUE32_64)
1118     void boxDouble(FPRReg fpr, GPRReg tagGPR, GPRReg payloadGPR)
1119     {
1120         moveDoubleToInts(fpr, payloadGPR, tagGPR);
1121     }
1122     void unboxDouble(GPRReg tagGPR, GPRReg payloadGPR, FPRReg fpr, FPRReg scratchFPR)
1123     {
1124         moveIntsToDouble(payloadGPR, tagGPR, fpr, scratchFPR);
1125     }
1126     
1127     void boxDouble(FPRReg fpr, JSValueRegs regs)
1128     {
1129         boxDouble(fpr, regs.tagGPR(), regs.payloadGPR());
1130     }
1131     void unboxDouble(JSValueRegs regs, FPRReg fpr, FPRReg scratchFPR)
1132     {
1133         unboxDouble(regs.tagGPR(), regs.payloadGPR(), fpr, scratchFPR);
1134     }
1135
1136     void unboxDoubleNonDestructive(const JSValueRegs regs, FPRReg destFPR, GPRReg, FPRReg scratchFPR)
1137     {
1138         unboxDouble(regs, destFPR, scratchFPR);
1139     }
1140 #endif
1141     
1142     void boxBooleanPayload(GPRReg boolGPR, GPRReg payloadGPR)
1143     {
1144 #if USE(JSVALUE64)
1145         add32(TrustedImm32(ValueFalse), boolGPR, payloadGPR);
1146 #else
1147         move(boolGPR, payloadGPR);
1148 #endif
1149     }
1150
1151     void boxBooleanPayload(bool value, GPRReg payloadGPR)
1152     {
1153 #if USE(JSVALUE64)
1154         move(TrustedImm32(ValueFalse + value), payloadGPR);
1155 #else
1156         move(TrustedImm32(value), payloadGPR);
1157 #endif
1158     }
1159
1160     void boxBoolean(GPRReg boolGPR, JSValueRegs boxedRegs)
1161     {
1162         boxBooleanPayload(boolGPR, boxedRegs.payloadGPR());
1163 #if USE(JSVALUE32_64)
1164         move(TrustedImm32(JSValue::BooleanTag), boxedRegs.tagGPR());
1165 #endif
1166     }
1167
1168     void boxInt32(GPRReg intGPR, JSValueRegs boxedRegs, TagRegistersMode mode = HaveTagRegisters)
1169     {
1170 #if USE(JSVALUE64)
1171         if (mode == DoNotHaveTagRegisters) {
1172             move(intGPR, boxedRegs.gpr());
1173             or64(TrustedImm64(TagTypeNumber), boxedRegs.gpr());
1174         } else
1175             or64(GPRInfo::tagTypeNumberRegister, intGPR, boxedRegs.gpr());
1176 #else
1177         UNUSED_PARAM(mode);
1178         move(intGPR, boxedRegs.payloadGPR());
1179         move(TrustedImm32(JSValue::Int32Tag), boxedRegs.tagGPR());
1180 #endif
1181     }
1182     
1183     void callExceptionFuzz();
1184     
1185     enum ExceptionCheckKind { NormalExceptionCheck, InvertedExceptionCheck };
1186     enum ExceptionJumpWidth { NormalJumpWidth, FarJumpWidth };
1187     Jump emitExceptionCheck(
1188         ExceptionCheckKind = NormalExceptionCheck, ExceptionJumpWidth = NormalJumpWidth);
1189     Jump emitNonPatchableExceptionCheck();
1190
1191 #if ENABLE(SAMPLING_COUNTERS)
1192     static void emitCount(MacroAssembler& jit, AbstractSamplingCounter& counter, int32_t increment = 1)
1193     {
1194         jit.add64(TrustedImm32(increment), AbsoluteAddress(counter.addressOfCounter()));
1195     }
1196     void emitCount(AbstractSamplingCounter& counter, int32_t increment = 1)
1197     {
1198         add64(TrustedImm32(increment), AbsoluteAddress(counter.addressOfCounter()));
1199     }
1200 #endif
1201
1202 #if ENABLE(SAMPLING_FLAGS)
1203     void setSamplingFlag(int32_t);
1204     void clearSamplingFlag(int32_t flag);
1205 #endif
1206
1207     JSGlobalObject* globalObjectFor(CodeOrigin codeOrigin)
1208     {
1209         return codeBlock()->globalObjectFor(codeOrigin);
1210     }
1211     
1212     bool isStrictModeFor(CodeOrigin codeOrigin)
1213     {
1214         if (!codeOrigin.inlineCallFrame)
1215             return codeBlock()->isStrictMode();
1216         return codeOrigin.inlineCallFrame->isStrictMode();
1217     }
1218     
1219     ECMAMode ecmaModeFor(CodeOrigin codeOrigin)
1220     {
1221         return isStrictModeFor(codeOrigin) ? StrictMode : NotStrictMode;
1222     }
1223     
1224     ExecutableBase* executableFor(const CodeOrigin& codeOrigin);
1225     
1226     CodeBlock* baselineCodeBlockFor(const CodeOrigin& codeOrigin)
1227     {
1228         return baselineCodeBlockForOriginAndBaselineCodeBlock(codeOrigin, baselineCodeBlock());
1229     }
1230     
1231     CodeBlock* baselineCodeBlockFor(InlineCallFrame* inlineCallFrame)
1232     {
1233         if (!inlineCallFrame)
1234             return baselineCodeBlock();
1235         return baselineCodeBlockForInlineCallFrame(inlineCallFrame);
1236     }
1237     
1238     CodeBlock* baselineCodeBlock()
1239     {
1240         return m_baselineCodeBlock;
1241     }
1242     
1243     static VirtualRegister argumentsStart(InlineCallFrame* inlineCallFrame)
1244     {
1245         if (!inlineCallFrame)
1246             return VirtualRegister(CallFrame::argumentOffset(0));
1247         if (inlineCallFrame->arguments.size() <= 1)
1248             return virtualRegisterForLocal(0);
1249         ValueRecovery recovery = inlineCallFrame->arguments[1];
1250         RELEASE_ASSERT(recovery.technique() == DisplacedInJSStack);
1251         return recovery.virtualRegister();
1252     }
1253     
1254     static VirtualRegister argumentsStart(const CodeOrigin& codeOrigin)
1255     {
1256         return argumentsStart(codeOrigin.inlineCallFrame);
1257     }
1258     
1259     void emitLoadStructure(RegisterID source, RegisterID dest, RegisterID scratch);
1260
1261     void emitStoreStructureWithTypeInfo(TrustedImmPtr structure, RegisterID dest, RegisterID)
1262     {
1263         emitStoreStructureWithTypeInfo(*this, structure, dest);
1264     }
1265
1266     void emitStoreStructureWithTypeInfo(RegisterID structure, RegisterID dest, RegisterID scratch)
1267     {
1268 #if USE(JSVALUE64)
1269         load64(MacroAssembler::Address(structure, Structure::structureIDOffset()), scratch);
1270         store64(scratch, MacroAssembler::Address(dest, JSCell::structureIDOffset()));
1271 #else
1272         // Store all the info flags using a single 32-bit wide load and store.
1273         load32(MacroAssembler::Address(structure, Structure::indexingTypeOffset()), scratch);
1274         store32(scratch, MacroAssembler::Address(dest, JSCell::indexingTypeOffset()));
1275
1276         // Store the StructureID
1277         storePtr(structure, MacroAssembler::Address(dest, JSCell::structureIDOffset()));
1278 #endif
1279     }
1280
1281     static void emitStoreStructureWithTypeInfo(AssemblyHelpers& jit, TrustedImmPtr structure, RegisterID dest);
1282
1283     Jump jumpIfIsRememberedOrInEden(GPRReg cell)
1284     {
1285         return branchTest8(MacroAssembler::NonZero, MacroAssembler::Address(cell, JSCell::cellStateOffset()));
1286     }
1287
1288     Jump jumpIfIsRememberedOrInEden(JSCell* cell)
1289     {
1290         uint8_t* address = reinterpret_cast<uint8_t*>(cell) + JSCell::cellStateOffset();
1291         return branchTest8(MacroAssembler::NonZero, MacroAssembler::AbsoluteAddress(address));
1292     }
1293     
1294     // Emits the branch structure for typeof. The code emitted by this doesn't fall through. The
1295     // functor is called at those points where we have pinpointed a type. One way to use this is to
1296     // have the functor emit the code to put the type string into an appropriate register and then
1297     // jump out. A secondary functor is used for the call trap and masquerades-as-undefined slow
1298     // case. It is passed the unlinked jump to the slow case.
1299     template<typename Functor, typename SlowPathFunctor>
1300     void emitTypeOf(
1301         JSValueRegs regs, GPRReg tempGPR, const Functor& functor,
1302         const SlowPathFunctor& slowPathFunctor)
1303     {
1304         // Implements the following branching structure:
1305         //
1306         // if (is cell) {
1307         //     if (is object) {
1308         //         if (is function) {
1309         //             return function;
1310         //         } else if (doesn't have call trap and doesn't masquerade as undefined) {
1311         //             return object
1312         //         } else {
1313         //             return slowPath();
1314         //         }
1315         //     } else if (is string) {
1316         //         return string
1317         //     } else {
1318         //         return symbol
1319         //     }
1320         // } else if (is number) {
1321         //     return number
1322         // } else if (is null) {
1323         //     return object
1324         // } else if (is boolean) {
1325         //     return boolean
1326         // } else {
1327         //     return undefined
1328         // }
1329         
1330         Jump notCell = branchIfNotCell(regs);
1331         
1332         GPRReg cellGPR = regs.payloadGPR();
1333         Jump notObject = branchIfNotObject(cellGPR);
1334         
1335         Jump notFunction = branchIfNotFunction(cellGPR);
1336         functor(TypeofType::Function, false);
1337         
1338         notFunction.link(this);
1339         slowPathFunctor(
1340             branchTest8(
1341                 NonZero,
1342                 Address(cellGPR, JSCell::typeInfoFlagsOffset()),
1343                 TrustedImm32(MasqueradesAsUndefined | TypeOfShouldCallGetCallData)));
1344         functor(TypeofType::Object, false);
1345         
1346         notObject.link(this);
1347         
1348         Jump notString = branchIfNotString(cellGPR);
1349         functor(TypeofType::String, false);
1350         notString.link(this);
1351         functor(TypeofType::Symbol, false);
1352         
1353         notCell.link(this);
1354
1355         Jump notNumber = branchIfNotNumber(regs, tempGPR);
1356         functor(TypeofType::Number, false);
1357         notNumber.link(this);
1358         
1359         JumpList notNull = branchIfNotEqual(regs, jsNull());
1360         functor(TypeofType::Object, false);
1361         notNull.link(this);
1362         
1363         Jump notBoolean = branchIfNotBoolean(regs, tempGPR);
1364         functor(TypeofType::Boolean, false);
1365         notBoolean.link(this);
1366         
1367         functor(TypeofType::Undefined, true);
1368     }
1369
1370     Vector<BytecodeAndMachineOffset>& decodedCodeMapFor(CodeBlock*);
1371
1372     void makeSpaceOnStackForCCall();
1373     void reclaimSpaceOnStackForCCall();
1374
1375 #if USE(JSVALUE64)
1376     void emitRandomThunk(JSGlobalObject*, GPRReg scratch0, GPRReg scratch1, GPRReg scratch2, FPRReg result);
1377     void emitRandomThunk(GPRReg scratch0, GPRReg scratch1, GPRReg scratch2, GPRReg scratch3, FPRReg result);
1378 #endif
1379     
1380 protected:
1381     VM* m_vm;
1382     CodeBlock* m_codeBlock;
1383     CodeBlock* m_baselineCodeBlock;
1384
1385     HashMap<CodeBlock*, Vector<BytecodeAndMachineOffset>> m_decodedCodeMaps;
1386 };
1387
1388 } // namespace JSC
1389
1390 #endif // ENABLE(JIT)
1391
1392 #endif // AssemblyHelpers_h
1393