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