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