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