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