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