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