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