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