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