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