d05c913319f91faa7d4c034fd8235af50c630185
[WebKit-https.git] / Source / JavaScriptCore / assembler / AbstractMacroAssembler.h
1 /*
2  * Copyright (C) 2008, 2012, 2014-2016 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 AbstractMacroAssembler_h
27 #define AbstractMacroAssembler_h
28
29 #include "AbortReason.h"
30 #include "CodeLocation.h"
31 #include "MacroAssemblerCodeRef.h"
32 #include "Options.h"
33 #include <wtf/CryptographicallyRandomNumber.h>
34 #include <wtf/Noncopyable.h>
35 #include <wtf/SharedTask.h>
36 #include <wtf/WeakRandom.h>
37
38 #if ENABLE(ASSEMBLER)
39
40 namespace JSC {
41
42 inline bool isARMv7IDIVSupported()
43 {
44 #if HAVE(ARM_IDIV_INSTRUCTIONS)
45     return true;
46 #else
47     return false;
48 #endif
49 }
50
51 inline bool isARM64()
52 {
53 #if CPU(ARM64)
54     return true;
55 #else
56     return false;
57 #endif
58 }
59
60 inline bool isX86()
61 {
62 #if CPU(X86_64) || CPU(X86)
63     return true;
64 #else
65     return false;
66 #endif
67 }
68
69 inline bool isX86_64()
70 {
71 #if CPU(X86_64)
72     return true;
73 #else
74     return false;
75 #endif
76 }
77
78 inline bool optimizeForARMv7IDIVSupported()
79 {
80     return isARMv7IDIVSupported() && Options::useArchitectureSpecificOptimizations();
81 }
82
83 inline bool optimizeForARM64()
84 {
85     return isARM64() && Options::useArchitectureSpecificOptimizations();
86 }
87
88 inline bool optimizeForX86()
89 {
90     return isX86() && Options::useArchitectureSpecificOptimizations();
91 }
92
93 inline bool optimizeForX86_64()
94 {
95     return isX86_64() && Options::useArchitectureSpecificOptimizations();
96 }
97
98 class AllowMacroScratchRegisterUsage;
99 class DisallowMacroScratchRegisterUsage;
100 class LinkBuffer;
101 class Watchpoint;
102 namespace DFG {
103 struct OSRExit;
104 }
105
106 template <class AssemblerType, class MacroAssemblerType>
107 class AbstractMacroAssembler {
108 public:
109     friend class JITWriteBarrierBase;
110     typedef AbstractMacroAssembler<AssemblerType, MacroAssemblerType> AbstractMacroAssemblerType;
111     typedef AssemblerType AssemblerType_T;
112
113     typedef MacroAssemblerCodePtr CodePtr;
114     typedef MacroAssemblerCodeRef CodeRef;
115
116     class Jump;
117
118     typedef typename AssemblerType::RegisterID RegisterID;
119     typedef typename AssemblerType::FPRegisterID FPRegisterID;
120     
121     static constexpr RegisterID firstRegister() { return AssemblerType::firstRegister(); }
122     static constexpr RegisterID lastRegister() { return AssemblerType::lastRegister(); }
123
124     static constexpr FPRegisterID firstFPRegister() { return AssemblerType::firstFPRegister(); }
125     static constexpr FPRegisterID lastFPRegister() { return AssemblerType::lastFPRegister(); }
126
127     // Section 1: MacroAssembler operand types
128     //
129     // The following types are used as operands to MacroAssembler operations,
130     // describing immediate  and memory operands to the instructions to be planted.
131
132     enum Scale {
133         TimesOne,
134         TimesTwo,
135         TimesFour,
136         TimesEight,
137     };
138     
139     static Scale timesPtr()
140     {
141         if (sizeof(void*) == 4)
142             return TimesFour;
143         return TimesEight;
144     }
145     
146     struct BaseIndex;
147     
148     // Address:
149     //
150     // Describes a simple base-offset address.
151     struct Address {
152         explicit Address(RegisterID base, int32_t offset = 0)
153             : base(base)
154             , offset(offset)
155         {
156         }
157         
158         Address withOffset(int32_t additionalOffset)
159         {
160             return Address(base, offset + additionalOffset);
161         }
162         
163         BaseIndex indexedBy(RegisterID index, Scale) const;
164         
165         RegisterID base;
166         int32_t offset;
167     };
168
169     struct ExtendedAddress {
170         explicit ExtendedAddress(RegisterID base, intptr_t offset = 0)
171             : base(base)
172             , offset(offset)
173         {
174         }
175         
176         RegisterID base;
177         intptr_t offset;
178     };
179
180     // ImplicitAddress:
181     //
182     // This class is used for explicit 'load' and 'store' operations
183     // (as opposed to situations in which a memory operand is provided
184     // to a generic operation, such as an integer arithmetic instruction).
185     //
186     // In the case of a load (or store) operation we want to permit
187     // addresses to be implicitly constructed, e.g. the two calls:
188     //
189     //     load32(Address(addrReg), destReg);
190     //     load32(addrReg, destReg);
191     //
192     // Are equivalent, and the explicit wrapping of the Address in the former
193     // is unnecessary.
194     struct ImplicitAddress {
195         ImplicitAddress(RegisterID base)
196             : base(base)
197             , offset(0)
198         {
199         }
200
201         ImplicitAddress(Address address)
202             : base(address.base)
203             , offset(address.offset)
204         {
205         }
206
207         RegisterID base;
208         int32_t offset;
209     };
210
211     // BaseIndex:
212     //
213     // Describes a complex addressing mode.
214     struct BaseIndex {
215         BaseIndex(RegisterID base, RegisterID index, Scale scale, int32_t offset = 0)
216             : base(base)
217             , index(index)
218             , scale(scale)
219             , offset(offset)
220         {
221         }
222         
223         RegisterID base;
224         RegisterID index;
225         Scale scale;
226         int32_t offset;
227         
228         BaseIndex withOffset(int32_t additionalOffset)
229         {
230             return BaseIndex(base, index, scale, offset + additionalOffset);
231         }
232     };
233
234     // AbsoluteAddress:
235     //
236     // Describes an memory operand given by a pointer.  For regular load & store
237     // operations an unwrapped void* will be used, rather than using this.
238     struct AbsoluteAddress {
239         explicit AbsoluteAddress(const void* ptr)
240             : m_ptr(ptr)
241         {
242         }
243
244         const void* m_ptr;
245     };
246
247     // TrustedImmPtr:
248     //
249     // A pointer sized immediate operand to an instruction - this is wrapped
250     // in a class requiring explicit construction in order to differentiate
251     // from pointers used as absolute addresses to memory operations
252     struct TrustedImmPtr {
253         TrustedImmPtr() { }
254         
255         explicit TrustedImmPtr(const void* value)
256             : m_value(value)
257         {
258         }
259         
260         // This is only here so that TrustedImmPtr(0) does not confuse the C++
261         // overload handling rules.
262         explicit TrustedImmPtr(int value)
263             : m_value(0)
264         {
265             ASSERT_UNUSED(value, !value);
266         }
267
268         explicit TrustedImmPtr(size_t value)
269             : m_value(reinterpret_cast<void*>(value))
270         {
271         }
272
273         intptr_t asIntptr()
274         {
275             return reinterpret_cast<intptr_t>(m_value);
276         }
277
278         const void* m_value;
279     };
280
281     struct ImmPtr : private TrustedImmPtr
282     {
283         explicit ImmPtr(const void* value)
284             : TrustedImmPtr(value)
285         {
286         }
287
288         TrustedImmPtr asTrustedImmPtr() { return *this; }
289     };
290
291     // TrustedImm32:
292     //
293     // A 32bit immediate operand to an instruction - this is wrapped in a
294     // class requiring explicit construction in order to prevent RegisterIDs
295     // (which are implemented as an enum) from accidentally being passed as
296     // immediate values.
297     struct TrustedImm32 {
298         TrustedImm32() { }
299         
300         explicit TrustedImm32(int32_t value)
301             : m_value(value)
302         {
303         }
304
305 #if !CPU(X86_64)
306         explicit TrustedImm32(TrustedImmPtr ptr)
307             : m_value(ptr.asIntptr())
308         {
309         }
310 #endif
311
312         int32_t m_value;
313     };
314
315
316     struct Imm32 : private TrustedImm32 {
317         explicit Imm32(int32_t value)
318             : TrustedImm32(value)
319         {
320         }
321 #if !CPU(X86_64)
322         explicit Imm32(TrustedImmPtr ptr)
323             : TrustedImm32(ptr)
324         {
325         }
326 #endif
327         const TrustedImm32& asTrustedImm32() const { return *this; }
328
329     };
330     
331     // TrustedImm64:
332     //
333     // A 64bit immediate operand to an instruction - this is wrapped in a
334     // class requiring explicit construction in order to prevent RegisterIDs
335     // (which are implemented as an enum) from accidentally being passed as
336     // immediate values.
337     struct TrustedImm64 {
338         TrustedImm64() { }
339         
340         explicit TrustedImm64(int64_t value)
341             : m_value(value)
342         {
343         }
344
345 #if CPU(X86_64) || CPU(ARM64)
346         explicit TrustedImm64(TrustedImmPtr ptr)
347             : m_value(ptr.asIntptr())
348         {
349         }
350 #endif
351
352         int64_t m_value;
353     };
354
355     struct Imm64 : private TrustedImm64
356     {
357         explicit Imm64(int64_t value)
358             : TrustedImm64(value)
359         {
360         }
361 #if CPU(X86_64) || CPU(ARM64)
362         explicit Imm64(TrustedImmPtr ptr)
363             : TrustedImm64(ptr)
364         {
365         }
366 #endif
367         const TrustedImm64& asTrustedImm64() const { return *this; }
368     };
369     
370     // Section 2: MacroAssembler code buffer handles
371     //
372     // The following types are used to reference items in the code buffer
373     // during JIT code generation.  For example, the type Jump is used to
374     // track the location of a jump instruction so that it may later be
375     // linked to a label marking its destination.
376
377
378     // Label:
379     //
380     // A Label records a point in the generated instruction stream, typically such that
381     // it may be used as a destination for a jump.
382     class Label {
383         template<class TemplateAssemblerType, class TemplateMacroAssemblerType>
384         friend class AbstractMacroAssembler;
385         friend struct DFG::OSRExit;
386         friend class Jump;
387         friend class MacroAssemblerCodeRef;
388         friend class LinkBuffer;
389         friend class Watchpoint;
390
391     public:
392         Label()
393         {
394         }
395
396         Label(AbstractMacroAssemblerType* masm)
397             : m_label(masm->m_assembler.label())
398         {
399             masm->invalidateAllTempRegisters();
400         }
401
402         bool operator==(const Label& other) const { return m_label == other.m_label; }
403
404         bool isSet() const { return m_label.isSet(); }
405     private:
406         AssemblerLabel m_label;
407     };
408     
409     // ConvertibleLoadLabel:
410     //
411     // A ConvertibleLoadLabel records a loadPtr instruction that can be patched to an addPtr
412     // so that:
413     //
414     // loadPtr(Address(a, i), b)
415     //
416     // becomes:
417     //
418     // addPtr(TrustedImmPtr(i), a, b)
419     class ConvertibleLoadLabel {
420         template<class TemplateAssemblerType, class TemplateMacroAssemblerType>
421         friend class AbstractMacroAssembler;
422         friend class LinkBuffer;
423         
424     public:
425         ConvertibleLoadLabel()
426         {
427         }
428         
429         ConvertibleLoadLabel(AbstractMacroAssemblerType* masm)
430             : m_label(masm->m_assembler.labelIgnoringWatchpoints())
431         {
432         }
433         
434         bool isSet() const { return m_label.isSet(); }
435     private:
436         AssemblerLabel m_label;
437     };
438
439     // DataLabelPtr:
440     //
441     // A DataLabelPtr is used to refer to a location in the code containing a pointer to be
442     // patched after the code has been generated.
443     class DataLabelPtr {
444         template<class TemplateAssemblerType, class TemplateMacroAssemblerType>
445         friend class AbstractMacroAssembler;
446         friend class LinkBuffer;
447     public:
448         DataLabelPtr()
449         {
450         }
451
452         DataLabelPtr(AbstractMacroAssemblerType* masm)
453             : m_label(masm->m_assembler.label())
454         {
455         }
456
457         bool isSet() const { return m_label.isSet(); }
458         
459     private:
460         AssemblerLabel m_label;
461     };
462
463     // DataLabel32:
464     //
465     // A DataLabel32 is used to refer to a location in the code containing a 32-bit constant to be
466     // patched after the code has been generated.
467     class DataLabel32 {
468         template<class TemplateAssemblerType, class TemplateMacroAssemblerType>
469         friend class AbstractMacroAssembler;
470         friend class LinkBuffer;
471     public:
472         DataLabel32()
473         {
474         }
475
476         DataLabel32(AbstractMacroAssemblerType* masm)
477             : m_label(masm->m_assembler.label())
478         {
479         }
480
481         AssemblerLabel label() const { return m_label; }
482
483     private:
484         AssemblerLabel m_label;
485     };
486
487     // DataLabelCompact:
488     //
489     // A DataLabelCompact is used to refer to a location in the code containing a
490     // compact immediate to be patched after the code has been generated.
491     class DataLabelCompact {
492         template<class TemplateAssemblerType, class TemplateMacroAssemblerType>
493         friend class AbstractMacroAssembler;
494         friend class LinkBuffer;
495     public:
496         DataLabelCompact()
497         {
498         }
499         
500         DataLabelCompact(AbstractMacroAssemblerType* masm)
501             : m_label(masm->m_assembler.label())
502         {
503         }
504
505         DataLabelCompact(AssemblerLabel label)
506             : m_label(label)
507         {
508         }
509
510         AssemblerLabel label() const { return m_label; }
511
512     private:
513         AssemblerLabel m_label;
514     };
515
516     // Call:
517     //
518     // A Call object is a reference to a call instruction that has been planted
519     // into the code buffer - it is typically used to link the call, setting the
520     // relative offset such that when executed it will call to the desired
521     // destination.
522     class Call {
523         template<class TemplateAssemblerType, class TemplateMacroAssemblerType>
524         friend class AbstractMacroAssembler;
525
526     public:
527         enum Flags {
528             None = 0x0,
529             Linkable = 0x1,
530             Near = 0x2,
531             Tail = 0x4,
532             LinkableNear = 0x3,
533             LinkableNearTail = 0x7,
534         };
535
536         Call()
537             : m_flags(None)
538         {
539         }
540         
541         Call(AssemblerLabel jmp, Flags flags)
542             : m_label(jmp)
543             , m_flags(flags)
544         {
545         }
546
547         bool isFlagSet(Flags flag)
548         {
549             return m_flags & flag;
550         }
551
552         static Call fromTailJump(Jump jump)
553         {
554             return Call(jump.m_label, Linkable);
555         }
556
557         AssemblerLabel m_label;
558     private:
559         Flags m_flags;
560     };
561
562     // Jump:
563     //
564     // A jump object is a reference to a jump instruction that has been planted
565     // into the code buffer - it is typically used to link the jump, setting the
566     // relative offset such that when executed it will jump to the desired
567     // destination.
568     class Jump {
569         template<class TemplateAssemblerType, class TemplateMacroAssemblerType>
570         friend class AbstractMacroAssembler;
571         friend class Call;
572         friend struct DFG::OSRExit;
573         friend class LinkBuffer;
574     public:
575         Jump()
576         {
577         }
578         
579 #if CPU(ARM_THUMB2)
580         // Fixme: this information should be stored in the instruction stream, not in the Jump object.
581         Jump(AssemblerLabel jmp, ARMv7Assembler::JumpType type = ARMv7Assembler::JumpNoCondition, ARMv7Assembler::Condition condition = ARMv7Assembler::ConditionInvalid)
582             : m_label(jmp)
583             , m_type(type)
584             , m_condition(condition)
585         {
586         }
587 #elif CPU(ARM64)
588         Jump(AssemblerLabel jmp, ARM64Assembler::JumpType type = ARM64Assembler::JumpNoCondition, ARM64Assembler::Condition condition = ARM64Assembler::ConditionInvalid)
589             : m_label(jmp)
590             , m_type(type)
591             , m_condition(condition)
592         {
593         }
594
595         Jump(AssemblerLabel jmp, ARM64Assembler::JumpType type, ARM64Assembler::Condition condition, bool is64Bit, ARM64Assembler::RegisterID compareRegister)
596             : m_label(jmp)
597             , m_type(type)
598             , m_condition(condition)
599             , m_is64Bit(is64Bit)
600             , m_compareRegister(compareRegister)
601         {
602             ASSERT((type == ARM64Assembler::JumpCompareAndBranch) || (type == ARM64Assembler::JumpCompareAndBranchFixedSize));
603         }
604
605         Jump(AssemblerLabel jmp, ARM64Assembler::JumpType type, ARM64Assembler::Condition condition, unsigned bitNumber, ARM64Assembler::RegisterID compareRegister)
606             : m_label(jmp)
607             , m_type(type)
608             , m_condition(condition)
609             , m_bitNumber(bitNumber)
610             , m_compareRegister(compareRegister)
611         {
612             ASSERT((type == ARM64Assembler::JumpTestBit) || (type == ARM64Assembler::JumpTestBitFixedSize));
613         }
614 #elif CPU(SH4)
615         Jump(AssemblerLabel jmp, SH4Assembler::JumpType type = SH4Assembler::JumpFar)
616             : m_label(jmp)
617             , m_type(type)
618         {
619         }
620 #else
621         Jump(AssemblerLabel jmp)    
622             : m_label(jmp)
623         {
624         }
625 #endif
626         
627         Label label() const
628         {
629             Label result;
630             result.m_label = m_label;
631             return result;
632         }
633
634         void link(AbstractMacroAssemblerType* masm) const
635         {
636             masm->invalidateAllTempRegisters();
637
638 #if ENABLE(DFG_REGISTER_ALLOCATION_VALIDATION)
639             masm->checkRegisterAllocationAgainstBranchRange(m_label.m_offset, masm->debugOffset());
640 #endif
641
642 #if CPU(ARM_THUMB2)
643             masm->m_assembler.linkJump(m_label, masm->m_assembler.label(), m_type, m_condition);
644 #elif CPU(ARM64)
645             if ((m_type == ARM64Assembler::JumpCompareAndBranch) || (m_type == ARM64Assembler::JumpCompareAndBranchFixedSize))
646                 masm->m_assembler.linkJump(m_label, masm->m_assembler.label(), m_type, m_condition, m_is64Bit, m_compareRegister);
647             else if ((m_type == ARM64Assembler::JumpTestBit) || (m_type == ARM64Assembler::JumpTestBitFixedSize))
648                 masm->m_assembler.linkJump(m_label, masm->m_assembler.label(), m_type, m_condition, m_bitNumber, m_compareRegister);
649             else
650                 masm->m_assembler.linkJump(m_label, masm->m_assembler.label(), m_type, m_condition);
651 #elif CPU(SH4)
652             masm->m_assembler.linkJump(m_label, masm->m_assembler.label(), m_type);
653 #else
654             masm->m_assembler.linkJump(m_label, masm->m_assembler.label());
655 #endif
656         }
657         
658         void linkTo(Label label, AbstractMacroAssemblerType* masm) const
659         {
660 #if ENABLE(DFG_REGISTER_ALLOCATION_VALIDATION)
661             masm->checkRegisterAllocationAgainstBranchRange(label.m_label.m_offset, m_label.m_offset);
662 #endif
663
664 #if CPU(ARM_THUMB2)
665             masm->m_assembler.linkJump(m_label, label.m_label, m_type, m_condition);
666 #elif CPU(ARM64)
667             if ((m_type == ARM64Assembler::JumpCompareAndBranch) || (m_type == ARM64Assembler::JumpCompareAndBranchFixedSize))
668                 masm->m_assembler.linkJump(m_label, label.m_label, m_type, m_condition, m_is64Bit, m_compareRegister);
669             else if ((m_type == ARM64Assembler::JumpTestBit) || (m_type == ARM64Assembler::JumpTestBitFixedSize))
670                 masm->m_assembler.linkJump(m_label, label.m_label, m_type, m_condition, m_bitNumber, m_compareRegister);
671             else
672                 masm->m_assembler.linkJump(m_label, label.m_label, m_type, m_condition);
673 #else
674             masm->m_assembler.linkJump(m_label, label.m_label);
675 #endif
676         }
677
678         bool isSet() const { return m_label.isSet(); }
679
680     private:
681         AssemblerLabel m_label;
682 #if CPU(ARM_THUMB2)
683         ARMv7Assembler::JumpType m_type;
684         ARMv7Assembler::Condition m_condition;
685 #elif CPU(ARM64)
686         ARM64Assembler::JumpType m_type;
687         ARM64Assembler::Condition m_condition;
688         bool m_is64Bit;
689         unsigned m_bitNumber;
690         ARM64Assembler::RegisterID m_compareRegister;
691 #endif
692 #if CPU(SH4)
693         SH4Assembler::JumpType m_type;
694 #endif
695     };
696
697     struct PatchableJump {
698         PatchableJump()
699         {
700         }
701
702         explicit PatchableJump(Jump jump)
703             : m_jump(jump)
704         {
705         }
706
707         operator Jump&() { return m_jump; }
708
709         Jump m_jump;
710     };
711
712     // JumpList:
713     //
714     // A JumpList is a set of Jump objects.
715     // All jumps in the set will be linked to the same destination.
716     class JumpList {
717     public:
718         typedef Vector<Jump, 2> JumpVector;
719         
720         JumpList() { }
721         
722         JumpList(Jump jump)
723         {
724             if (jump.isSet())
725                 append(jump);
726         }
727
728         void link(AbstractMacroAssemblerType* masm) const
729         {
730             size_t size = m_jumps.size();
731             for (size_t i = 0; i < size; ++i)
732                 m_jumps[i].link(masm);
733         }
734         
735         void linkTo(Label label, AbstractMacroAssemblerType* masm) const
736         {
737             size_t size = m_jumps.size();
738             for (size_t i = 0; i < size; ++i)
739                 m_jumps[i].linkTo(label, masm);
740         }
741         
742         void append(Jump jump)
743         {
744             m_jumps.append(jump);
745         }
746         
747         void append(const JumpList& other)
748         {
749             m_jumps.append(other.m_jumps.begin(), other.m_jumps.size());
750         }
751
752         bool empty()
753         {
754             return !m_jumps.size();
755         }
756         
757         void clear()
758         {
759             m_jumps.clear();
760         }
761         
762         const JumpVector& jumps() const { return m_jumps; }
763
764     private:
765         JumpVector m_jumps;
766     };
767
768
769     // Section 3: Misc admin methods
770 #if ENABLE(DFG_JIT)
771     Label labelIgnoringWatchpoints()
772     {
773         Label result;
774         result.m_label = m_assembler.labelIgnoringWatchpoints();
775         return result;
776     }
777 #else
778     Label labelIgnoringWatchpoints()
779     {
780         return label();
781     }
782 #endif
783     
784     Label label()
785     {
786         return Label(this);
787     }
788     
789     void padBeforePatch()
790     {
791         // Rely on the fact that asking for a label already does the padding.
792         (void)label();
793     }
794     
795     Label watchpointLabel()
796     {
797         Label result;
798         result.m_label = m_assembler.labelForWatchpoint();
799         return result;
800     }
801     
802     Label align()
803     {
804         m_assembler.align(16);
805         return Label(this);
806     }
807
808 #if ENABLE(DFG_REGISTER_ALLOCATION_VALIDATION)
809     class RegisterAllocationOffset {
810     public:
811         RegisterAllocationOffset(unsigned offset)
812             : m_offset(offset)
813         {
814         }
815
816         void checkOffsets(unsigned low, unsigned high)
817         {
818             RELEASE_ASSERT_WITH_MESSAGE(!(low <= m_offset && m_offset <= high), "Unsafe branch over register allocation at instruction offset %u in jump offset range %u..%u", m_offset, low, high);
819         }
820
821     private:
822         unsigned m_offset;
823     };
824
825     void addRegisterAllocationAtOffset(unsigned offset)
826     {
827         m_registerAllocationForOffsets.append(RegisterAllocationOffset(offset));
828     }
829
830     void clearRegisterAllocationOffsets()
831     {
832         m_registerAllocationForOffsets.clear();
833     }
834
835     void checkRegisterAllocationAgainstBranchRange(unsigned offset1, unsigned offset2)
836     {
837         if (offset1 > offset2)
838             std::swap(offset1, offset2);
839
840         size_t size = m_registerAllocationForOffsets.size();
841         for (size_t i = 0; i < size; ++i)
842             m_registerAllocationForOffsets[i].checkOffsets(offset1, offset2);
843     }
844 #endif
845
846     template<typename T, typename U>
847     static ptrdiff_t differenceBetween(T from, U to)
848     {
849         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label);
850     }
851
852     static ptrdiff_t differenceBetweenCodePtr(const MacroAssemblerCodePtr& a, const MacroAssemblerCodePtr& b)
853     {
854         return reinterpret_cast<ptrdiff_t>(b.executableAddress()) - reinterpret_cast<ptrdiff_t>(a.executableAddress());
855     }
856
857     unsigned debugOffset() { return m_assembler.debugOffset(); }
858
859     ALWAYS_INLINE static void cacheFlush(void* code, size_t size)
860     {
861         AssemblerType::cacheFlush(code, size);
862     }
863
864 #if ENABLE(MASM_PROBE)
865
866     struct CPUState {
867         #define DECLARE_REGISTER(_type, _regName) \
868             _type _regName;
869         FOR_EACH_CPU_REGISTER(DECLARE_REGISTER)
870         #undef DECLARE_REGISTER
871
872         static const char* gprName(RegisterID regID)
873         {
874             switch (regID) {
875                 #define DECLARE_REGISTER(_type, _regName) \
876                 case RegisterID::_regName: \
877                     return #_regName;
878                 FOR_EACH_CPU_GPREGISTER(DECLARE_REGISTER)
879                 #undef DECLARE_REGISTER
880             default:
881                 RELEASE_ASSERT_NOT_REACHED();
882             }
883         }
884
885         static const char* fprName(FPRegisterID regID)
886         {
887             switch (regID) {
888                 #define DECLARE_REGISTER(_type, _regName) \
889                 case FPRegisterID::_regName: \
890                     return #_regName;
891                 FOR_EACH_CPU_FPREGISTER(DECLARE_REGISTER)
892                 #undef DECLARE_REGISTER
893             default:
894                 RELEASE_ASSERT_NOT_REACHED();
895             }
896         }
897
898         void*& gpr(RegisterID regID)
899         {
900             switch (regID) {
901                 #define DECLARE_REGISTER(_type, _regName) \
902                 case RegisterID::_regName: \
903                     return _regName;
904                 FOR_EACH_CPU_GPREGISTER(DECLARE_REGISTER)
905                 #undef DECLARE_REGISTER
906             default:
907                 RELEASE_ASSERT_NOT_REACHED();
908             }
909         }
910
911         double& fpr(FPRegisterID regID)
912         {
913             switch (regID) {
914                 #define DECLARE_REGISTER(_type, _regName) \
915                 case FPRegisterID::_regName: \
916                     return _regName;
917                 FOR_EACH_CPU_FPREGISTER(DECLARE_REGISTER)
918                 #undef DECLARE_REGISTER
919             default:
920                 RELEASE_ASSERT_NOT_REACHED();
921             }
922         }
923     };
924
925     struct ProbeContext;
926     typedef void (*ProbeFunction)(struct ProbeContext*);
927
928     struct ProbeContext {
929         ProbeFunction probeFunction;
930         void* arg1;
931         void* arg2;
932         CPUState cpu;
933
934         // Convenience methods:
935         void*& gpr(RegisterID regID) { return cpu.gpr(regID); }
936         double& fpr(FPRegisterID regID) { return cpu.fpr(regID); }
937         const char* gprName(RegisterID regID) { return cpu.gprName(regID); }
938         const char* fprName(FPRegisterID regID) { return cpu.fprName(regID); }
939     };
940
941     // This function emits code to preserve the CPUState (e.g. registers),
942     // call a user supplied probe function, and restore the CPUState before
943     // continuing with other JIT generated code.
944     //
945     // The user supplied probe function will be called with a single pointer to
946     // a ProbeContext struct (defined above) which contains, among other things,
947     // the preserved CPUState. This allows the user probe function to inspect
948     // the CPUState at that point in the JIT generated code.
949     //
950     // If the user probe function alters the register values in the ProbeContext,
951     // the altered values will be loaded into the CPU registers when the probe
952     // returns.
953     //
954     // The ProbeContext is stack allocated and is only valid for the duration
955     // of the call to the user probe function.
956     //
957     // Note: probe() should be implemented by the target specific MacroAssembler.
958     // This prototype is only provided here to document the interface.
959
960     void probe(ProbeFunction, void* arg1, void* arg2);
961
962 #endif // ENABLE(MASM_PROBE)
963
964     AssemblerType m_assembler;
965     
966     static void linkJump(void* code, Jump jump, CodeLocationLabel target)
967     {
968         AssemblerType::linkJump(code, jump.m_label, target.dataLocation());
969     }
970
971     static void linkPointer(void* code, AssemblerLabel label, void* value)
972     {
973         AssemblerType::linkPointer(code, label, value);
974     }
975
976     static void* getLinkerAddress(void* code, AssemblerLabel label)
977     {
978         return AssemblerType::getRelocatedAddress(code, label);
979     }
980
981     static unsigned getLinkerCallReturnOffset(Call call)
982     {
983         return AssemblerType::getCallReturnOffset(call.m_label);
984     }
985
986     static void repatchJump(CodeLocationJump jump, CodeLocationLabel destination)
987     {
988         AssemblerType::relinkJump(jump.dataLocation(), destination.dataLocation());
989     }
990
991     static void repatchNearCall(CodeLocationNearCall nearCall, CodeLocationLabel destination)
992     {
993         switch (nearCall.callMode()) {
994         case NearCallMode::Tail:
995             AssemblerType::relinkJump(nearCall.dataLocation(), destination.dataLocation());
996             return;
997         case NearCallMode::Regular:
998             AssemblerType::relinkCall(nearCall.dataLocation(), destination.executableAddress());
999             return;
1000         }
1001         RELEASE_ASSERT_NOT_REACHED();
1002     }
1003
1004     static void repatchCompact(CodeLocationDataLabelCompact dataLabelCompact, int32_t value)
1005     {
1006         AssemblerType::repatchCompact(dataLabelCompact.dataLocation(), value);
1007     }
1008     
1009     static void repatchInt32(CodeLocationDataLabel32 dataLabel32, int32_t value)
1010     {
1011         AssemblerType::repatchInt32(dataLabel32.dataLocation(), value);
1012     }
1013
1014     static void repatchPointer(CodeLocationDataLabelPtr dataLabelPtr, void* value)
1015     {
1016         AssemblerType::repatchPointer(dataLabelPtr.dataLocation(), value);
1017     }
1018     
1019     static void* readPointer(CodeLocationDataLabelPtr dataLabelPtr)
1020     {
1021         return AssemblerType::readPointer(dataLabelPtr.dataLocation());
1022     }
1023     
1024     static void replaceWithLoad(CodeLocationConvertibleLoad label)
1025     {
1026         AssemblerType::replaceWithLoad(label.dataLocation());
1027     }
1028     
1029     static void replaceWithAddressComputation(CodeLocationConvertibleLoad label)
1030     {
1031         AssemblerType::replaceWithAddressComputation(label.dataLocation());
1032     }
1033
1034     template<typename Functor>
1035     void addLinkTask(const Functor& functor)
1036     {
1037         m_linkTasks.append(createSharedTask<void(LinkBuffer&)>(functor));
1038     }
1039
1040     void emitNops(size_t memoryToFillWithNopsInBytes)
1041     {
1042         AssemblerBuffer& buffer = m_assembler.buffer();
1043         size_t startCodeSize = buffer.codeSize();
1044         size_t targetCodeSize = startCodeSize + memoryToFillWithNopsInBytes;
1045         buffer.ensureSpace(memoryToFillWithNopsInBytes);
1046         bool isCopyingToExecutableMemory = false;
1047         AssemblerType::fillNops(static_cast<char*>(buffer.data()) + startCodeSize, memoryToFillWithNopsInBytes, isCopyingToExecutableMemory);
1048         buffer.setCodeSize(targetCodeSize);
1049     }
1050
1051 protected:
1052     AbstractMacroAssembler()
1053         : m_randomSource(0)
1054     {
1055         invalidateAllTempRegisters();
1056     }
1057
1058     uint32_t random()
1059     {
1060         if (!m_randomSourceIsInitialized) {
1061             m_randomSourceIsInitialized = true;
1062             m_randomSource.setSeed(cryptographicallyRandomNumber());
1063         }
1064         return m_randomSource.getUint32();
1065     }
1066
1067     bool m_randomSourceIsInitialized { false };
1068     WeakRandom m_randomSource;
1069
1070 #if ENABLE(DFG_REGISTER_ALLOCATION_VALIDATION)
1071     Vector<RegisterAllocationOffset, 10> m_registerAllocationForOffsets;
1072 #endif
1073
1074     static bool haveScratchRegisterForBlinding()
1075     {
1076         return false;
1077     }
1078     static RegisterID scratchRegisterForBlinding()
1079     {
1080         UNREACHABLE_FOR_PLATFORM();
1081         return firstRegister();
1082     }
1083     static bool canBlind() { return false; }
1084     static bool shouldBlindForSpecificArch(uint32_t) { return false; }
1085     static bool shouldBlindForSpecificArch(uint64_t) { return false; }
1086
1087     class CachedTempRegister {
1088         friend class DataLabelPtr;
1089         friend class DataLabel32;
1090         friend class DataLabelCompact;
1091         friend class Jump;
1092         friend class Label;
1093
1094     public:
1095         CachedTempRegister(AbstractMacroAssemblerType* masm, RegisterID registerID)
1096             : m_masm(masm)
1097             , m_registerID(registerID)
1098             , m_value(0)
1099             , m_validBit(1 << static_cast<unsigned>(registerID))
1100         {
1101             ASSERT(static_cast<unsigned>(registerID) < (sizeof(unsigned) * 8));
1102         }
1103
1104         ALWAYS_INLINE RegisterID registerIDInvalidate() { invalidate(); return m_registerID; }
1105
1106         ALWAYS_INLINE RegisterID registerIDNoInvalidate() { return m_registerID; }
1107
1108         bool value(intptr_t& value)
1109         {
1110             value = m_value;
1111             return m_masm->isTempRegisterValid(m_validBit);
1112         }
1113
1114         void setValue(intptr_t value)
1115         {
1116             m_value = value;
1117             m_masm->setTempRegisterValid(m_validBit);
1118         }
1119
1120         ALWAYS_INLINE void invalidate() { m_masm->clearTempRegisterValid(m_validBit); }
1121
1122     private:
1123         AbstractMacroAssemblerType* m_masm;
1124         RegisterID m_registerID;
1125         intptr_t m_value;
1126         unsigned m_validBit;
1127     };
1128
1129     ALWAYS_INLINE void invalidateAllTempRegisters()
1130     {
1131         m_tempRegistersValidBits = 0;
1132     }
1133
1134     ALWAYS_INLINE bool isTempRegisterValid(unsigned registerMask)
1135     {
1136         return (m_tempRegistersValidBits & registerMask);
1137     }
1138
1139     ALWAYS_INLINE void clearTempRegisterValid(unsigned registerMask)
1140     {
1141         m_tempRegistersValidBits &=  ~registerMask;
1142     }
1143
1144     ALWAYS_INLINE void setTempRegisterValid(unsigned registerMask)
1145     {
1146         m_tempRegistersValidBits |= registerMask;
1147     }
1148
1149     friend class AllowMacroScratchRegisterUsage;
1150     friend class DisallowMacroScratchRegisterUsage;
1151     unsigned m_tempRegistersValidBits;
1152     bool m_allowScratchRegister { true };
1153
1154     Vector<RefPtr<SharedTask<void(LinkBuffer&)>>> m_linkTasks;
1155
1156     friend class LinkBuffer;
1157 }; // class AbstractMacroAssembler
1158
1159 template <class AssemblerType, class MacroAssemblerType>
1160 inline typename AbstractMacroAssembler<AssemblerType, MacroAssemblerType>::BaseIndex
1161 AbstractMacroAssembler<AssemblerType, MacroAssemblerType>::Address::indexedBy(
1162     typename AbstractMacroAssembler<AssemblerType, MacroAssemblerType>::RegisterID index,
1163     typename AbstractMacroAssembler<AssemblerType, MacroAssemblerType>::Scale scale) const
1164 {
1165     return BaseIndex(base, index, scale, offset);
1166 }
1167
1168 } // namespace JSC
1169
1170 #endif // ENABLE(ASSEMBLER)
1171
1172 #endif // AbstractMacroAssembler_h