f87b467b1087b8c3ee839a1ccc481e89273cecf9
[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 "JSCPtrTag.h"
35 #include "MacroAssemblerCodeRef.h"
36 #include "MacroAssemblerHelpers.h"
37 #include "Options.h"
38 #include <wtf/CryptographicallyRandomNumber.h>
39 #include <wtf/Noncopyable.h>
40 #include <wtf/SharedTask.h>
41 #include <wtf/Vector.h>
42 #include <wtf/WeakRandom.h>
43
44 namespace JSC {
45
46 #if ENABLE(ASSEMBLER)
47
48 class AllowMacroScratchRegisterUsage;
49 class DisallowMacroScratchRegisterUsage;
50 class LinkBuffer;
51 class Watchpoint;
52 namespace DFG {
53 struct OSRExit;
54 }
55
56 class AbstractMacroAssemblerBase {
57     WTF_MAKE_FAST_ALLOCATED;
58 public:
59     enum StatusCondition {
60         Success,
61         Failure
62     };
63     
64     static StatusCondition invert(StatusCondition condition)
65     {
66         switch (condition) {
67         case Success:
68             return Failure;
69         case Failure:
70             return Success;
71         }
72         RELEASE_ASSERT_NOT_REACHED();
73         return Success;
74     }
75 };
76
77 template <class AssemblerType>
78 class AbstractMacroAssembler : public AbstractMacroAssemblerBase {
79 public:
80     typedef AbstractMacroAssembler<AssemblerType> AbstractMacroAssemblerType;
81     typedef AssemblerType AssemblerType_T;
82
83     template<PtrTag tag> using CodePtr = MacroAssemblerCodePtr<tag>;
84     template<PtrTag tag> using CodeRef = MacroAssemblerCodeRef<tag>;
85
86     enum class CPUIDCheckState {
87         NotChecked,
88         Clear,
89         Set
90     };
91
92     class Jump;
93
94     typedef typename AssemblerType::RegisterID RegisterID;
95     typedef typename AssemblerType::SPRegisterID SPRegisterID;
96     typedef typename AssemblerType::FPRegisterID FPRegisterID;
97     
98     static constexpr RegisterID firstRegister() { return AssemblerType::firstRegister(); }
99     static constexpr RegisterID lastRegister() { return AssemblerType::lastRegister(); }
100     static constexpr unsigned numberOfRegisters() { return AssemblerType::numberOfRegisters(); }
101     static const char* gprName(RegisterID id) { return AssemblerType::gprName(id); }
102
103     static constexpr SPRegisterID firstSPRegister() { return AssemblerType::firstSPRegister(); }
104     static constexpr SPRegisterID lastSPRegister() { return AssemblerType::lastSPRegister(); }
105     static constexpr unsigned numberOfSPRegisters() { return AssemblerType::numberOfSPRegisters(); }
106     static const char* sprName(SPRegisterID id) { return AssemblerType::sprName(id); }
107
108     static constexpr FPRegisterID firstFPRegister() { return AssemblerType::firstFPRegister(); }
109     static constexpr FPRegisterID lastFPRegister() { return AssemblerType::lastFPRegister(); }
110     static constexpr unsigned numberOfFPRegisters() { return AssemblerType::numberOfFPRegisters(); }
111     static const char* fprName(FPRegisterID id) { return AssemblerType::fprName(id); }
112
113     // Section 1: MacroAssembler operand types
114     //
115     // The following types are used as operands to MacroAssembler operations,
116     // describing immediate  and memory operands to the instructions to be planted.
117
118     enum Scale {
119         TimesOne,
120         TimesTwo,
121         TimesFour,
122         TimesEight,
123     };
124     
125     static Scale timesPtr()
126     {
127         if (sizeof(void*) == 4)
128             return TimesFour;
129         return TimesEight;
130     }
131     
132     struct BaseIndex;
133     
134     static RegisterID withSwappedRegister(RegisterID original, RegisterID left, RegisterID right)
135     {
136         if (original == left)
137             return right;
138         if (original == right)
139             return left;
140         return original;
141     }
142     
143     // Address:
144     //
145     // Describes a simple base-offset address.
146     struct Address {
147         explicit Address(RegisterID base, int32_t offset = 0)
148             : base(base)
149             , offset(offset)
150         {
151         }
152         
153         Address withOffset(int32_t additionalOffset)
154         {
155             return Address(base, offset + additionalOffset);
156         }
157         
158         Address withSwappedRegister(RegisterID left, RegisterID right)
159         {
160             return Address(AbstractMacroAssembler::withSwappedRegister(base, left, right), offset);
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         BaseIndex withSwappedRegister(RegisterID left, RegisterID right)
234         {
235             return BaseIndex(AbstractMacroAssembler::withSwappedRegister(base, left, right), AbstractMacroAssembler::withSwappedRegister(index, left, right), scale, offset);
236         }
237     };
238
239     // AbsoluteAddress:
240     //
241     // Describes an memory operand given by a pointer.  For regular load & store
242     // operations an unwrapped void* will be used, rather than using this.
243     struct AbsoluteAddress {
244         explicit AbsoluteAddress(const void* ptr)
245             : m_ptr(ptr)
246         {
247         }
248
249         const void* m_ptr;
250     };
251
252     // TrustedImm:
253     //
254     // An empty super class of each of the TrustedImm types. This class is used for template overloads
255     // on a TrustedImm type via std::is_base_of.
256     struct TrustedImm { };
257
258     // TrustedImmPtr:
259     //
260     // A pointer sized immediate operand to an instruction - this is wrapped
261     // in a class requiring explicit construction in order to differentiate
262     // from pointers used as absolute addresses to memory operations
263     struct TrustedImmPtr : public TrustedImm {
264         TrustedImmPtr() { }
265         
266         explicit TrustedImmPtr(const void* value)
267             : m_value(value)
268         {
269         }
270
271         template<typename ReturnType, typename... Arguments>
272         explicit TrustedImmPtr(ReturnType(*value)(Arguments...))
273             : m_value(reinterpret_cast<void*>(value))
274         {
275         }
276
277         explicit TrustedImmPtr(std::nullptr_t)
278         {
279         }
280
281         explicit TrustedImmPtr(size_t value)
282             : m_value(reinterpret_cast<void*>(value))
283         {
284         }
285
286         intptr_t asIntptr()
287         {
288             return reinterpret_cast<intptr_t>(m_value);
289         }
290
291         void* asPtr()
292         {
293             return const_cast<void*>(m_value);
294         }
295
296         const void* m_value { 0 };
297     };
298
299     struct ImmPtr : private TrustedImmPtr
300     {
301         explicit ImmPtr(const void* value)
302             : TrustedImmPtr(value)
303         {
304         }
305
306         TrustedImmPtr asTrustedImmPtr() { return *this; }
307     };
308
309     // TrustedImm32:
310     //
311     // A 32bit immediate operand to an instruction - this is wrapped in a
312     // class requiring explicit construction in order to prevent RegisterIDs
313     // (which are implemented as an enum) from accidentally being passed as
314     // immediate values.
315     struct TrustedImm32 : public TrustedImm {
316         TrustedImm32() { }
317         
318         explicit TrustedImm32(int32_t value)
319             : m_value(value)
320         {
321         }
322
323 #if !CPU(X86_64)
324         explicit TrustedImm32(TrustedImmPtr ptr)
325             : m_value(ptr.asIntptr())
326         {
327         }
328 #endif
329
330         int32_t m_value;
331     };
332
333
334     struct Imm32 : private TrustedImm32 {
335         explicit Imm32(int32_t value)
336             : TrustedImm32(value)
337         {
338         }
339 #if !CPU(X86_64)
340         explicit Imm32(TrustedImmPtr ptr)
341             : TrustedImm32(ptr)
342         {
343         }
344 #endif
345         const TrustedImm32& asTrustedImm32() const { return *this; }
346
347     };
348     
349     // TrustedImm64:
350     //
351     // A 64bit immediate operand to an instruction - this is wrapped in a
352     // class requiring explicit construction in order to prevent RegisterIDs
353     // (which are implemented as an enum) from accidentally being passed as
354     // immediate values.
355     struct TrustedImm64 : TrustedImm {
356         TrustedImm64() { }
357         
358         explicit TrustedImm64(int64_t value)
359             : m_value(value)
360         {
361         }
362
363 #if CPU(X86_64) || CPU(ARM64)
364         explicit TrustedImm64(TrustedImmPtr ptr)
365             : m_value(ptr.asIntptr())
366         {
367         }
368 #endif
369
370         int64_t m_value;
371     };
372
373     struct Imm64 : private TrustedImm64
374     {
375         explicit Imm64(int64_t value)
376             : TrustedImm64(value)
377         {
378         }
379 #if CPU(X86_64) || CPU(ARM64)
380         explicit Imm64(TrustedImmPtr ptr)
381             : TrustedImm64(ptr)
382         {
383         }
384 #endif
385         const TrustedImm64& asTrustedImm64() const { return *this; }
386     };
387     
388     // Section 2: MacroAssembler code buffer handles
389     //
390     // The following types are used to reference items in the code buffer
391     // during JIT code generation.  For example, the type Jump is used to
392     // track the location of a jump instruction so that it may later be
393     // linked to a label marking its destination.
394
395
396     // Label:
397     //
398     // A Label records a point in the generated instruction stream, typically such that
399     // it may be used as a destination for a jump.
400     class Label {
401         friend class AbstractMacroAssembler<AssemblerType>;
402         friend struct DFG::OSRExit;
403         friend class Jump;
404         template<PtrTag> friend class MacroAssemblerCodeRef;
405         friend class LinkBuffer;
406         friend class Watchpoint;
407
408     public:
409         Label()
410         {
411         }
412
413         Label(AbstractMacroAssemblerType* masm)
414             : m_label(masm->m_assembler.label())
415         {
416             masm->invalidateAllTempRegisters();
417         }
418
419         bool operator==(const Label& other) const { return m_label == other.m_label; }
420
421         bool isSet() const { return m_label.isSet(); }
422     private:
423         AssemblerLabel m_label;
424     };
425     
426     // ConvertibleLoadLabel:
427     //
428     // A ConvertibleLoadLabel records a loadPtr instruction that can be patched to an addPtr
429     // so that:
430     //
431     // loadPtr(Address(a, i), b)
432     //
433     // becomes:
434     //
435     // addPtr(TrustedImmPtr(i), a, b)
436     class ConvertibleLoadLabel {
437         friend class AbstractMacroAssembler<AssemblerType>;
438         friend class LinkBuffer;
439         
440     public:
441         ConvertibleLoadLabel()
442         {
443         }
444         
445         ConvertibleLoadLabel(AbstractMacroAssemblerType* masm)
446             : m_label(masm->m_assembler.labelIgnoringWatchpoints())
447         {
448         }
449         
450         bool isSet() const { return m_label.isSet(); }
451     private:
452         AssemblerLabel m_label;
453     };
454
455     // DataLabelPtr:
456     //
457     // A DataLabelPtr is used to refer to a location in the code containing a pointer to be
458     // patched after the code has been generated.
459     class DataLabelPtr {
460         friend class AbstractMacroAssembler<AssemblerType>;
461         friend class LinkBuffer;
462     public:
463         DataLabelPtr()
464         {
465         }
466
467         DataLabelPtr(AbstractMacroAssemblerType* masm)
468             : m_label(masm->m_assembler.label())
469         {
470         }
471
472         bool isSet() const { return m_label.isSet(); }
473         
474     private:
475         AssemblerLabel m_label;
476     };
477
478     // DataLabel32:
479     //
480     // A DataLabel32 is used to refer to a location in the code containing a 32-bit constant to be
481     // patched after the code has been generated.
482     class DataLabel32 {
483         friend class AbstractMacroAssembler<AssemblerType>;
484         friend class LinkBuffer;
485     public:
486         DataLabel32()
487         {
488         }
489
490         DataLabel32(AbstractMacroAssemblerType* masm)
491             : m_label(masm->m_assembler.label())
492         {
493         }
494
495         AssemblerLabel label() const { return m_label; }
496
497     private:
498         AssemblerLabel m_label;
499     };
500
501     // DataLabelCompact:
502     //
503     // A DataLabelCompact is used to refer to a location in the code containing a
504     // compact immediate to be patched after the code has been generated.
505     class DataLabelCompact {
506         friend class AbstractMacroAssembler<AssemblerType>;
507         friend class LinkBuffer;
508     public:
509         DataLabelCompact()
510         {
511         }
512         
513         DataLabelCompact(AbstractMacroAssemblerType* masm)
514             : m_label(masm->m_assembler.label())
515         {
516         }
517
518         DataLabelCompact(AssemblerLabel label)
519             : m_label(label)
520         {
521         }
522
523         AssemblerLabel label() const { return m_label; }
524
525     private:
526         AssemblerLabel m_label;
527     };
528
529     // Call:
530     //
531     // A Call object is a reference to a call instruction that has been planted
532     // into the code buffer - it is typically used to link the call, setting the
533     // relative offset such that when executed it will call to the desired
534     // destination.
535     class Call {
536         friend class AbstractMacroAssembler<AssemblerType>;
537
538     public:
539         enum Flags {
540             None = 0x0,
541             Linkable = 0x1,
542             Near = 0x2,
543             Tail = 0x4,
544             LinkableNear = 0x3,
545             LinkableNearTail = 0x7,
546         };
547
548         Call()
549             : m_flags(None)
550         {
551         }
552         
553         Call(AssemblerLabel jmp, Flags flags)
554             : m_label(jmp)
555             , m_flags(flags)
556         {
557         }
558
559         bool isFlagSet(Flags flag)
560         {
561             return m_flags & flag;
562         }
563
564         static Call fromTailJump(Jump jump)
565         {
566             return Call(jump.m_label, Linkable);
567         }
568
569         AssemblerLabel m_label;
570     private:
571         Flags m_flags;
572     };
573
574     // Jump:
575     //
576     // A jump object is a reference to a jump instruction that has been planted
577     // into the code buffer - it is typically used to link the jump, setting the
578     // relative offset such that when executed it will jump to the desired
579     // destination.
580     class Jump {
581         friend class AbstractMacroAssembler<AssemblerType>;
582         friend class Call;
583         friend struct DFG::OSRExit;
584         friend class LinkBuffer;
585     public:
586         Jump()
587         {
588         }
589         
590 #if CPU(ARM_THUMB2)
591         // Fixme: this information should be stored in the instruction stream, not in the Jump object.
592         Jump(AssemblerLabel jmp, ARMv7Assembler::JumpType type = ARMv7Assembler::JumpNoCondition, ARMv7Assembler::Condition condition = ARMv7Assembler::ConditionInvalid)
593             : m_label(jmp)
594             , m_type(type)
595             , m_condition(condition)
596         {
597         }
598 #elif CPU(ARM64)
599         Jump(AssemblerLabel jmp, ARM64Assembler::JumpType type = ARM64Assembler::JumpNoCondition, ARM64Assembler::Condition condition = ARM64Assembler::ConditionInvalid)
600             : m_label(jmp)
601             , m_type(type)
602             , m_condition(condition)
603         {
604         }
605
606         Jump(AssemblerLabel jmp, ARM64Assembler::JumpType type, ARM64Assembler::Condition condition, bool is64Bit, ARM64Assembler::RegisterID compareRegister)
607             : m_label(jmp)
608             , m_type(type)
609             , m_condition(condition)
610             , m_is64Bit(is64Bit)
611             , m_compareRegister(compareRegister)
612         {
613             ASSERT((type == ARM64Assembler::JumpCompareAndBranch) || (type == ARM64Assembler::JumpCompareAndBranchFixedSize));
614         }
615
616         Jump(AssemblerLabel jmp, ARM64Assembler::JumpType type, ARM64Assembler::Condition condition, unsigned bitNumber, ARM64Assembler::RegisterID compareRegister)
617             : m_label(jmp)
618             , m_type(type)
619             , m_condition(condition)
620             , m_bitNumber(bitNumber)
621             , m_compareRegister(compareRegister)
622         {
623             ASSERT((type == ARM64Assembler::JumpTestBit) || (type == ARM64Assembler::JumpTestBitFixedSize));
624         }
625 #else
626         Jump(AssemblerLabel jmp)    
627             : m_label(jmp)
628         {
629         }
630 #endif
631         
632         Label label() const
633         {
634             Label result;
635             result.m_label = m_label;
636             return result;
637         }
638
639         void link(AbstractMacroAssemblerType* masm) const
640         {
641             masm->invalidateAllTempRegisters();
642
643 #if ENABLE(DFG_REGISTER_ALLOCATION_VALIDATION)
644             masm->checkRegisterAllocationAgainstBranchRange(m_label.m_offset, masm->debugOffset());
645 #endif
646
647 #if CPU(ARM_THUMB2)
648             masm->m_assembler.linkJump(m_label, masm->m_assembler.label(), m_type, m_condition);
649 #elif CPU(ARM64)
650             if ((m_type == ARM64Assembler::JumpCompareAndBranch) || (m_type == ARM64Assembler::JumpCompareAndBranchFixedSize))
651                 masm->m_assembler.linkJump(m_label, masm->m_assembler.label(), m_type, m_condition, m_is64Bit, m_compareRegister);
652             else if ((m_type == ARM64Assembler::JumpTestBit) || (m_type == ARM64Assembler::JumpTestBitFixedSize))
653                 masm->m_assembler.linkJump(m_label, masm->m_assembler.label(), m_type, m_condition, m_bitNumber, m_compareRegister);
654             else
655                 masm->m_assembler.linkJump(m_label, masm->m_assembler.label(), m_type, m_condition);
656 #else
657             masm->m_assembler.linkJump(m_label, masm->m_assembler.label());
658 #endif
659         }
660         
661         void linkTo(Label label, AbstractMacroAssemblerType* masm) const
662         {
663 #if ENABLE(DFG_REGISTER_ALLOCATION_VALIDATION)
664             masm->checkRegisterAllocationAgainstBranchRange(label.m_label.m_offset, m_label.m_offset);
665 #endif
666
667 #if CPU(ARM_THUMB2)
668             masm->m_assembler.linkJump(m_label, label.m_label, m_type, m_condition);
669 #elif CPU(ARM64)
670             if ((m_type == ARM64Assembler::JumpCompareAndBranch) || (m_type == ARM64Assembler::JumpCompareAndBranchFixedSize))
671                 masm->m_assembler.linkJump(m_label, label.m_label, m_type, m_condition, m_is64Bit, m_compareRegister);
672             else if ((m_type == ARM64Assembler::JumpTestBit) || (m_type == ARM64Assembler::JumpTestBitFixedSize))
673                 masm->m_assembler.linkJump(m_label, label.m_label, m_type, m_condition, m_bitNumber, m_compareRegister);
674             else
675                 masm->m_assembler.linkJump(m_label, label.m_label, m_type, m_condition);
676 #else
677             masm->m_assembler.linkJump(m_label, label.m_label);
678 #endif
679         }
680
681         bool isSet() const { return m_label.isSet(); }
682
683     private:
684         AssemblerLabel m_label;
685 #if CPU(ARM_THUMB2)
686         ARMv7Assembler::JumpType m_type;
687         ARMv7Assembler::Condition m_condition;
688 #elif CPU(ARM64)
689         ARM64Assembler::JumpType m_type;
690         ARM64Assembler::Condition m_condition;
691         bool m_is64Bit;
692         unsigned m_bitNumber;
693         ARM64Assembler::RegisterID m_compareRegister;
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             if (jump.isSet())
745                 m_jumps.append(jump);
746         }
747         
748         void append(const JumpList& other)
749         {
750             m_jumps.append(other.m_jumps.begin(), other.m_jumps.size());
751         }
752
753         bool empty() const
754         {
755             return !m_jumps.size();
756         }
757         
758         void clear()
759         {
760             m_jumps.clear();
761         }
762         
763         const JumpVector& jumps() const { return m_jumps; }
764
765     private:
766         JumpVector m_jumps;
767     };
768
769
770     // Section 3: Misc admin methods
771 #if ENABLE(DFG_JIT)
772     Label labelIgnoringWatchpoints()
773     {
774         Label result;
775         result.m_label = m_assembler.labelIgnoringWatchpoints();
776         return result;
777     }
778 #else
779     Label labelIgnoringWatchpoints()
780     {
781         return label();
782     }
783 #endif
784     
785     Label label()
786     {
787         return Label(this);
788     }
789     
790     void padBeforePatch()
791     {
792         // Rely on the fact that asking for a label already does the padding.
793         (void)label();
794     }
795     
796     Label watchpointLabel()
797     {
798         Label result;
799         result.m_label = m_assembler.labelForWatchpoint();
800         return result;
801     }
802     
803     Label align()
804     {
805         m_assembler.align(16);
806         return Label(this);
807     }
808
809 #if ENABLE(DFG_REGISTER_ALLOCATION_VALIDATION)
810     class RegisterAllocationOffset {
811     public:
812         RegisterAllocationOffset(unsigned offset)
813             : m_offset(offset)
814         {
815         }
816
817         void checkOffsets(unsigned low, unsigned high)
818         {
819             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);
820         }
821
822     private:
823         unsigned m_offset;
824     };
825
826     void addRegisterAllocationAtOffset(unsigned offset)
827     {
828         m_registerAllocationForOffsets.append(RegisterAllocationOffset(offset));
829     }
830
831     void clearRegisterAllocationOffsets()
832     {
833         m_registerAllocationForOffsets.clear();
834     }
835
836     void checkRegisterAllocationAgainstBranchRange(unsigned offset1, unsigned offset2)
837     {
838         if (offset1 > offset2)
839             std::swap(offset1, offset2);
840
841         size_t size = m_registerAllocationForOffsets.size();
842         for (size_t i = 0; i < size; ++i)
843             m_registerAllocationForOffsets[i].checkOffsets(offset1, offset2);
844     }
845 #endif
846
847     template<typename T, typename U>
848     static ptrdiff_t differenceBetween(T from, U to)
849     {
850         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label);
851     }
852
853     template<PtrTag aTag, PtrTag bTag>
854     static ptrdiff_t differenceBetweenCodePtr(const MacroAssemblerCodePtr<aTag>& a, const MacroAssemblerCodePtr<bTag>& b)
855     {
856         return b.template dataLocation<ptrdiff_t>() - a.template dataLocation<ptrdiff_t>();
857     }
858
859     unsigned debugOffset() { return m_assembler.debugOffset(); }
860
861     ALWAYS_INLINE static void cacheFlush(void* code, size_t size)
862     {
863         AssemblerType::cacheFlush(code, size);
864     }
865
866     template<PtrTag tag>
867     static void linkJump(void* code, Jump jump, CodeLocationLabel<tag> target)
868     {
869         AssemblerType::linkJump(code, jump.m_label, target.dataLocation());
870     }
871
872     static void linkPointer(void* code, AssemblerLabel label, void* value)
873     {
874         AssemblerType::linkPointer(code, label, value);
875     }
876
877     template<PtrTag tag>
878     static void linkPointer(void* code, AssemblerLabel label, MacroAssemblerCodePtr<tag> value)
879     {
880         AssemblerType::linkPointer(code, label, value.executableAddress());
881     }
882
883     template<PtrTag tag>
884     static void* getLinkerAddress(void* code, AssemblerLabel label)
885     {
886         return tagCodePtr(AssemblerType::getRelocatedAddress(code, label), tag);
887     }
888
889     static unsigned getLinkerCallReturnOffset(Call call)
890     {
891         return AssemblerType::getCallReturnOffset(call.m_label);
892     }
893
894     template<PtrTag jumpTag, PtrTag destTag>
895     static void repatchJump(CodeLocationJump<jumpTag> jump, CodeLocationLabel<destTag> destination)
896     {
897         AssemblerType::relinkJump(jump.dataLocation(), destination.dataLocation());
898     }
899     
900     template<PtrTag jumpTag>
901     static void repatchJumpToNop(CodeLocationJump<jumpTag> jump)
902     {
903         AssemblerType::relinkJumpToNop(jump.dataLocation());
904     }
905
906     template<PtrTag callTag, PtrTag destTag>
907     static void repatchNearCall(CodeLocationNearCall<callTag> nearCall, CodeLocationLabel<destTag> destination)
908     {
909         switch (nearCall.callMode()) {
910         case NearCallMode::Tail:
911             AssemblerType::relinkJump(nearCall.dataLocation(), destination.dataLocation());
912             return;
913         case NearCallMode::Regular:
914             AssemblerType::relinkCall(nearCall.dataLocation(), destination.untaggedExecutableAddress());
915             return;
916         }
917         RELEASE_ASSERT_NOT_REACHED();
918     }
919
920     template<PtrTag tag>
921     static void repatchCompact(CodeLocationDataLabelCompact<tag> dataLabelCompact, int32_t value)
922     {
923         AssemblerType::repatchCompact(dataLabelCompact.template dataLocation(), value);
924     }
925
926     template<PtrTag tag>
927     static void repatchInt32(CodeLocationDataLabel32<tag> dataLabel32, int32_t value)
928     {
929         AssemblerType::repatchInt32(dataLabel32.dataLocation(), value);
930     }
931
932     template<PtrTag tag>
933     static void repatchPointer(CodeLocationDataLabelPtr<tag> dataLabelPtr, void* value)
934     {
935         AssemblerType::repatchPointer(dataLabelPtr.dataLocation(), value);
936     }
937
938     template<PtrTag tag>
939     static void* readPointer(CodeLocationDataLabelPtr<tag> dataLabelPtr)
940     {
941         return AssemblerType::readPointer(dataLabelPtr.dataLocation());
942     }
943     
944     template<PtrTag tag>
945     static void replaceWithLoad(CodeLocationConvertibleLoad<tag> label)
946     {
947         AssemblerType::replaceWithLoad(label.dataLocation());
948     }
949
950     template<PtrTag tag>
951     static void replaceWithAddressComputation(CodeLocationConvertibleLoad<tag> label)
952     {
953         AssemblerType::replaceWithAddressComputation(label.dataLocation());
954     }
955
956     template<typename Functor>
957     void addLinkTask(const Functor& functor)
958     {
959         m_linkTasks.append(createSharedTask<void(LinkBuffer&)>(functor));
960     }
961
962     void emitNops(size_t memoryToFillWithNopsInBytes)
963     {
964 #if CPU(ARM64)
965         RELEASE_ASSERT(memoryToFillWithNopsInBytes % 4 == 0);
966         for (unsigned i = 0; i < memoryToFillWithNopsInBytes / 4; ++i)
967             m_assembler.nop();
968 #else
969         AssemblerBuffer& buffer = m_assembler.buffer();
970         size_t startCodeSize = buffer.codeSize();
971         size_t targetCodeSize = startCodeSize + memoryToFillWithNopsInBytes;
972         buffer.ensureSpace(memoryToFillWithNopsInBytes);
973         AssemblerType::fillNops(static_cast<char*>(buffer.data()) + startCodeSize, memoryToFillWithNopsInBytes, memcpy);
974         buffer.setCodeSize(targetCodeSize);
975 #endif
976     }
977
978     ALWAYS_INLINE void tagReturnAddress() { }
979     ALWAYS_INLINE void untagReturnAddress() { }
980
981     ALWAYS_INLINE void tagPtr(PtrTag, RegisterID) { }
982     ALWAYS_INLINE void tagPtr(RegisterID, RegisterID) { }
983     ALWAYS_INLINE void untagPtr(PtrTag, RegisterID) { }
984     ALWAYS_INLINE void untagPtr(RegisterID, RegisterID) { }
985     ALWAYS_INLINE void removePtrTag(RegisterID) { }
986
987 protected:
988     AbstractMacroAssembler()
989         : m_randomSource(0)
990         , m_assembler()
991     {
992         invalidateAllTempRegisters();
993     }
994
995     uint32_t random()
996     {
997         if (!m_randomSourceIsInitialized) {
998             m_randomSourceIsInitialized = true;
999             m_randomSource.setSeed(cryptographicallyRandomNumber());
1000         }
1001         return m_randomSource.getUint32();
1002     }
1003
1004     bool m_randomSourceIsInitialized { false };
1005     WeakRandom m_randomSource;
1006 public:
1007     AssemblerType m_assembler;
1008 protected:
1009
1010 #if ENABLE(DFG_REGISTER_ALLOCATION_VALIDATION)
1011     Vector<RegisterAllocationOffset, 10> m_registerAllocationForOffsets;
1012 #endif
1013
1014     static bool haveScratchRegisterForBlinding()
1015     {
1016         return false;
1017     }
1018     static RegisterID scratchRegisterForBlinding()
1019     {
1020         UNREACHABLE_FOR_PLATFORM();
1021         return firstRegister();
1022     }
1023     static bool canBlind() { return false; }
1024     static bool shouldBlindForSpecificArch(uint32_t) { return false; }
1025     static bool shouldBlindForSpecificArch(uint64_t) { return false; }
1026
1027     class CachedTempRegister {
1028         friend class DataLabelPtr;
1029         friend class DataLabel32;
1030         friend class DataLabelCompact;
1031         friend class Jump;
1032         friend class Label;
1033
1034     public:
1035         CachedTempRegister(AbstractMacroAssemblerType* masm, RegisterID registerID)
1036             : m_masm(masm)
1037             , m_registerID(registerID)
1038             , m_value(0)
1039             , m_validBit(1 << static_cast<unsigned>(registerID))
1040         {
1041             ASSERT(static_cast<unsigned>(registerID) < (sizeof(unsigned) * 8));
1042         }
1043
1044         ALWAYS_INLINE RegisterID registerIDInvalidate() { invalidate(); return m_registerID; }
1045
1046         ALWAYS_INLINE RegisterID registerIDNoInvalidate() { return m_registerID; }
1047
1048         bool value(intptr_t& value)
1049         {
1050             value = m_value;
1051             return m_masm->isTempRegisterValid(m_validBit);
1052         }
1053
1054         void setValue(intptr_t value)
1055         {
1056             m_value = value;
1057             m_masm->setTempRegisterValid(m_validBit);
1058         }
1059
1060         ALWAYS_INLINE void invalidate() { m_masm->clearTempRegisterValid(m_validBit); }
1061
1062     private:
1063         AbstractMacroAssemblerType* m_masm;
1064         RegisterID m_registerID;
1065         intptr_t m_value;
1066         unsigned m_validBit;
1067     };
1068
1069     ALWAYS_INLINE void invalidateAllTempRegisters()
1070     {
1071         m_tempRegistersValidBits = 0;
1072     }
1073
1074     ALWAYS_INLINE bool isTempRegisterValid(unsigned registerMask)
1075     {
1076         return (m_tempRegistersValidBits & registerMask);
1077     }
1078
1079     ALWAYS_INLINE void clearTempRegisterValid(unsigned registerMask)
1080     {
1081         m_tempRegistersValidBits &=  ~registerMask;
1082     }
1083
1084     ALWAYS_INLINE void setTempRegisterValid(unsigned registerMask)
1085     {
1086         m_tempRegistersValidBits |= registerMask;
1087     }
1088
1089     friend class AllowMacroScratchRegisterUsage;
1090     friend class AllowMacroScratchRegisterUsageIf;
1091     friend class DisallowMacroScratchRegisterUsage;
1092     unsigned m_tempRegistersValidBits;
1093     bool m_allowScratchRegister { true };
1094
1095     Vector<RefPtr<SharedTask<void(LinkBuffer&)>>> m_linkTasks;
1096
1097     friend class LinkBuffer;
1098 }; // class AbstractMacroAssembler
1099
1100 template <class AssemblerType>
1101 inline typename AbstractMacroAssembler<AssemblerType>::BaseIndex
1102 AbstractMacroAssembler<AssemblerType>::Address::indexedBy(
1103     typename AbstractMacroAssembler<AssemblerType>::RegisterID index,
1104     typename AbstractMacroAssembler<AssemblerType>::Scale scale) const
1105 {
1106     return BaseIndex(base, index, scale, offset);
1107 }
1108
1109 #endif // ENABLE(ASSEMBLER)
1110
1111 } // namespace JSC
1112
1113 #if ENABLE(ASSEMBLER)
1114
1115 namespace WTF {
1116
1117 class PrintStream;
1118
1119 void printInternal(PrintStream& out, JSC::AbstractMacroAssemblerBase::StatusCondition);
1120
1121 } // namespace WTF
1122
1123 #endif // ENABLE(ASSEMBLER)
1124