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