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