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