Unreviewed, rolling out r149349 and r149354.
[WebKit-https.git] / Source / JavaScriptCore / assembler / AbstractMacroAssembler.h
1 /*
2  * Copyright (C) 2008, 2012 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 "AssemblerBuffer.h"
30 #include "CodeLocation.h"
31 #include "MacroAssemblerCodeRef.h"
32 #include <wtf/CryptographicallyRandomNumber.h>
33 #include <wtf/Noncopyable.h>
34 #include <wtf/UnusedParam.h>
35
36 #if ENABLE(ASSEMBLER)
37
38
39 #if PLATFORM(QT)
40 #define ENABLE_JIT_CONSTANT_BLINDING 0
41 #endif
42
43 #ifndef ENABLE_JIT_CONSTANT_BLINDING
44 #define ENABLE_JIT_CONSTANT_BLINDING 1
45 #endif
46
47 namespace JSC {
48
49 inline bool isARMv7s()
50 {
51 #if CPU(APPLE_ARMV7S)
52     return true;
53 #else
54     return false;
55 #endif
56 }
57
58 inline bool isX86()
59 {
60 #if CPU(X86_64) || CPU(X86)
61     return true;
62 #else
63     return false;
64 #endif
65 }
66
67 class JumpReplacementWatchpoint;
68 class LinkBuffer;
69 class RepatchBuffer;
70 class Watchpoint;
71 namespace DFG {
72 struct OSRExit;
73 }
74
75 template <class AssemblerType>
76 class AbstractMacroAssembler {
77 public:
78     friend class JITWriteBarrierBase;
79     typedef AssemblerType AssemblerType_T;
80
81     typedef MacroAssemblerCodePtr CodePtr;
82     typedef MacroAssemblerCodeRef CodeRef;
83
84     class Jump;
85
86     typedef typename AssemblerType::RegisterID RegisterID;
87
88     // Section 1: MacroAssembler operand types
89     //
90     // The following types are used as operands to MacroAssembler operations,
91     // describing immediate  and memory operands to the instructions to be planted.
92
93     enum Scale {
94         TimesOne,
95         TimesTwo,
96         TimesFour,
97         TimesEight,
98     };
99
100     // Address:
101     //
102     // Describes a simple base-offset address.
103     struct Address {
104         explicit Address(RegisterID base, int32_t offset = 0)
105             : base(base)
106             , offset(offset)
107         {
108         }
109
110         RegisterID base;
111         int32_t offset;
112     };
113
114     struct ExtendedAddress {
115         explicit ExtendedAddress(RegisterID base, intptr_t offset = 0)
116             : base(base)
117             , offset(offset)
118         {
119         }
120         
121         RegisterID base;
122         intptr_t offset;
123     };
124
125     // ImplicitAddress:
126     //
127     // This class is used for explicit 'load' and 'store' operations
128     // (as opposed to situations in which a memory operand is provided
129     // to a generic operation, such as an integer arithmetic instruction).
130     //
131     // In the case of a load (or store) operation we want to permit
132     // addresses to be implicitly constructed, e.g. the two calls:
133     //
134     //     load32(Address(addrReg), destReg);
135     //     load32(addrReg, destReg);
136     //
137     // Are equivalent, and the explicit wrapping of the Address in the former
138     // is unnecessary.
139     struct ImplicitAddress {
140         ImplicitAddress(RegisterID base)
141             : base(base)
142             , offset(0)
143         {
144         }
145
146         ImplicitAddress(Address address)
147             : base(address.base)
148             , offset(address.offset)
149         {
150         }
151
152         RegisterID base;
153         int32_t offset;
154     };
155
156     // BaseIndex:
157     //
158     // Describes a complex addressing mode.
159     struct BaseIndex {
160         BaseIndex(RegisterID base, RegisterID index, Scale scale, int32_t offset = 0)
161             : base(base)
162             , index(index)
163             , scale(scale)
164             , offset(offset)
165         {
166         }
167
168         RegisterID base;
169         RegisterID index;
170         Scale scale;
171         int32_t offset;
172     };
173
174     // AbsoluteAddress:
175     //
176     // Describes an memory operand given by a pointer.  For regular load & store
177     // operations an unwrapped void* will be used, rather than using this.
178     struct AbsoluteAddress {
179         explicit AbsoluteAddress(const void* ptr)
180             : m_ptr(ptr)
181         {
182         }
183
184         const void* m_ptr;
185     };
186
187     // TrustedImmPtr:
188     //
189     // A pointer sized immediate operand to an instruction - this is wrapped
190     // in a class requiring explicit construction in order to differentiate
191     // from pointers used as absolute addresses to memory operations
192     struct TrustedImmPtr {
193         TrustedImmPtr() { }
194         
195         explicit TrustedImmPtr(const void* value)
196             : m_value(value)
197         {
198         }
199         
200         // This is only here so that TrustedImmPtr(0) does not confuse the C++
201         // overload handling rules.
202         explicit TrustedImmPtr(int value)
203             : m_value(0)
204         {
205             ASSERT_UNUSED(value, !value);
206         }
207
208         explicit TrustedImmPtr(size_t value)
209             : m_value(reinterpret_cast<void*>(value))
210         {
211         }
212
213         intptr_t asIntptr()
214         {
215             return reinterpret_cast<intptr_t>(m_value);
216         }
217
218         const void* m_value;
219     };
220
221     struct ImmPtr : 
222 #if ENABLE(JIT_CONSTANT_BLINDING)
223         private TrustedImmPtr 
224 #else
225         public TrustedImmPtr
226 #endif
227     {
228         explicit ImmPtr(const void* value)
229             : TrustedImmPtr(value)
230         {
231         }
232
233         TrustedImmPtr asTrustedImmPtr() { return *this; }
234     };
235
236     // TrustedImm32:
237     //
238     // A 32bit immediate operand to an instruction - this is wrapped in a
239     // class requiring explicit construction in order to prevent RegisterIDs
240     // (which are implemented as an enum) from accidentally being passed as
241     // immediate values.
242     struct TrustedImm32 {
243         TrustedImm32() { }
244         
245         explicit TrustedImm32(int32_t value)
246             : m_value(value)
247         {
248         }
249
250 #if !CPU(X86_64)
251         explicit TrustedImm32(TrustedImmPtr ptr)
252             : m_value(ptr.asIntptr())
253         {
254         }
255 #endif
256
257         int32_t m_value;
258     };
259
260
261     struct Imm32 : 
262 #if ENABLE(JIT_CONSTANT_BLINDING)
263         private TrustedImm32 
264 #else
265         public TrustedImm32
266 #endif
267     {
268         explicit Imm32(int32_t value)
269             : TrustedImm32(value)
270         {
271         }
272 #if !CPU(X86_64)
273         explicit Imm32(TrustedImmPtr ptr)
274             : TrustedImm32(ptr)
275         {
276         }
277 #endif
278         const TrustedImm32& asTrustedImm32() const { return *this; }
279
280     };
281     
282     // TrustedImm64:
283     //
284     // A 64bit immediate operand to an instruction - this is wrapped in a
285     // class requiring explicit construction in order to prevent RegisterIDs
286     // (which are implemented as an enum) from accidentally being passed as
287     // immediate values.
288     struct TrustedImm64 {
289         TrustedImm64() { }
290         
291         explicit TrustedImm64(int64_t value)
292             : m_value(value)
293         {
294         }
295
296 #if CPU(X86_64)
297         explicit TrustedImm64(TrustedImmPtr ptr)
298             : m_value(ptr.asIntptr())
299         {
300         }
301 #endif
302
303         int64_t m_value;
304     };
305
306     struct Imm64 : 
307 #if ENABLE(JIT_CONSTANT_BLINDING)
308         private TrustedImm64 
309 #else
310         public TrustedImm64
311 #endif
312     {
313         explicit Imm64(int64_t value)
314             : TrustedImm64(value)
315         {
316         }
317 #if CPU(X86_64)
318         explicit Imm64(TrustedImmPtr ptr)
319             : TrustedImm64(ptr)
320         {
321         }
322 #endif
323         const TrustedImm64& asTrustedImm64() const { return *this; }
324     };
325     
326     // Section 2: MacroAssembler code buffer handles
327     //
328     // The following types are used to reference items in the code buffer
329     // during JIT code generation.  For example, the type Jump is used to
330     // track the location of a jump instruction so that it may later be
331     // linked to a label marking its destination.
332
333
334     // Label:
335     //
336     // A Label records a point in the generated instruction stream, typically such that
337     // it may be used as a destination for a jump.
338     class Label {
339         template<class TemplateAssemblerType>
340         friend class AbstractMacroAssembler;
341         friend struct DFG::OSRExit;
342         friend class Jump;
343         friend class JumpReplacementWatchpoint;
344         friend class MacroAssemblerCodeRef;
345         friend class LinkBuffer;
346         friend class Watchpoint;
347
348     public:
349         Label()
350         {
351         }
352
353         Label(AbstractMacroAssembler<AssemblerType>* masm)
354             : m_label(masm->m_assembler.label())
355         {
356         }
357         
358         bool isSet() const { return m_label.isSet(); }
359     private:
360         AssemblerLabel m_label;
361     };
362     
363     // ConvertibleLoadLabel:
364     //
365     // A ConvertibleLoadLabel records a loadPtr instruction that can be patched to an addPtr
366     // so that:
367     //
368     // loadPtr(Address(a, i), b)
369     //
370     // becomes:
371     //
372     // addPtr(TrustedImmPtr(i), a, b)
373     class ConvertibleLoadLabel {
374         template<class TemplateAssemblerType>
375         friend class AbstractMacroAssembler;
376         friend class LinkBuffer;
377         
378     public:
379         ConvertibleLoadLabel()
380         {
381         }
382         
383         ConvertibleLoadLabel(AbstractMacroAssembler<AssemblerType>* masm)
384             : m_label(masm->m_assembler.labelIgnoringWatchpoints())
385         {
386         }
387         
388         bool isSet() const { return m_label.isSet(); }
389     private:
390         AssemblerLabel m_label;
391     };
392
393     // DataLabelPtr:
394     //
395     // A DataLabelPtr is used to refer to a location in the code containing a pointer to be
396     // patched after the code has been generated.
397     class DataLabelPtr {
398         template<class TemplateAssemblerType>
399         friend class AbstractMacroAssembler;
400         friend class LinkBuffer;
401     public:
402         DataLabelPtr()
403         {
404         }
405
406         DataLabelPtr(AbstractMacroAssembler<AssemblerType>* masm)
407             : m_label(masm->m_assembler.label())
408         {
409         }
410         
411         bool isSet() const { return m_label.isSet(); }
412         
413     private:
414         AssemblerLabel m_label;
415     };
416
417     // DataLabel32:
418     //
419     // A DataLabelPtr is used to refer to a location in the code containing a pointer to be
420     // patched after the code has been generated.
421     class DataLabel32 {
422         template<class TemplateAssemblerType>
423         friend class AbstractMacroAssembler;
424         friend class LinkBuffer;
425     public:
426         DataLabel32()
427         {
428         }
429
430         DataLabel32(AbstractMacroAssembler<AssemblerType>* masm)
431             : m_label(masm->m_assembler.label())
432         {
433         }
434
435         AssemblerLabel label() const { return m_label; }
436
437     private:
438         AssemblerLabel m_label;
439     };
440
441     // DataLabelCompact:
442     //
443     // A DataLabelCompact is used to refer to a location in the code containing a
444     // compact immediate to be patched after the code has been generated.
445     class DataLabelCompact {
446         template<class TemplateAssemblerType>
447         friend class AbstractMacroAssembler;
448         friend class LinkBuffer;
449     public:
450         DataLabelCompact()
451         {
452         }
453         
454         DataLabelCompact(AbstractMacroAssembler<AssemblerType>* masm)
455             : m_label(masm->m_assembler.label())
456         {
457         }
458     
459         DataLabelCompact(AssemblerLabel label)
460             : m_label(label)
461         {
462         }
463
464     private:
465         AssemblerLabel m_label;
466     };
467
468     // Call:
469     //
470     // A Call object is a reference to a call instruction that has been planted
471     // into the code buffer - it is typically used to link the call, setting the
472     // relative offset such that when executed it will call to the desired
473     // destination.
474     class Call {
475         template<class TemplateAssemblerType>
476         friend class AbstractMacroAssembler;
477
478     public:
479         enum Flags {
480             None = 0x0,
481             Linkable = 0x1,
482             Near = 0x2,
483             LinkableNear = 0x3,
484         };
485
486         Call()
487             : m_flags(None)
488         {
489         }
490         
491         Call(AssemblerLabel jmp, Flags flags)
492             : m_label(jmp)
493             , m_flags(flags)
494         {
495         }
496
497         bool isFlagSet(Flags flag)
498         {
499             return m_flags & flag;
500         }
501
502         static Call fromTailJump(Jump jump)
503         {
504             return Call(jump.m_label, Linkable);
505         }
506
507         AssemblerLabel m_label;
508     private:
509         Flags m_flags;
510     };
511
512     // Jump:
513     //
514     // A jump object is a reference to a jump instruction that has been planted
515     // into the code buffer - it is typically used to link the jump, setting the
516     // relative offset such that when executed it will jump to the desired
517     // destination.
518     class Jump {
519         template<class TemplateAssemblerType>
520         friend class AbstractMacroAssembler;
521         friend class Call;
522         friend struct DFG::OSRExit;
523         friend class LinkBuffer;
524     public:
525         Jump()
526         {
527         }
528         
529 #if CPU(ARM_THUMB2)
530         // Fixme: this information should be stored in the instruction stream, not in the Jump object.
531         Jump(AssemblerLabel jmp, ARMv7Assembler::JumpType type = ARMv7Assembler::JumpNoCondition, ARMv7Assembler::Condition condition = ARMv7Assembler::ConditionInvalid)
532             : m_label(jmp)
533             , m_type(type)
534             , m_condition(condition)
535         {
536         }
537 #elif CPU(SH4)
538         Jump(AssemblerLabel jmp, SH4Assembler::JumpType type = SH4Assembler::JumpFar)
539             : m_label(jmp)
540             , m_type(type)
541         {
542         }
543 #else
544         Jump(AssemblerLabel jmp)    
545             : m_label(jmp)
546         {
547         }
548 #endif
549         
550         Label label() const
551         {
552             Label result;
553             result.m_label = m_label;
554             return result;
555         }
556
557         void link(AbstractMacroAssembler<AssemblerType>* masm) const
558         {
559 #if ENABLE(DFG_REGISTER_ALLOCATION_VALIDATION)
560             masm->checkRegisterAllocationAgainstBranchRange(m_label.m_offset, masm->debugOffset());
561 #endif
562
563 #if CPU(ARM_THUMB2)
564             masm->m_assembler.linkJump(m_label, masm->m_assembler.label(), m_type, m_condition);
565 #elif CPU(SH4)
566             masm->m_assembler.linkJump(m_label, masm->m_assembler.label(), m_type);
567 #else
568             masm->m_assembler.linkJump(m_label, masm->m_assembler.label());
569 #endif
570         }
571         
572         void linkTo(Label label, AbstractMacroAssembler<AssemblerType>* masm) const
573         {
574 #if ENABLE(DFG_REGISTER_ALLOCATION_VALIDATION)
575             masm->checkRegisterAllocationAgainstBranchRange(label.m_label.m_offset, m_label.m_offset);
576 #endif
577
578 #if CPU(ARM_THUMB2)
579             masm->m_assembler.linkJump(m_label, label.m_label, m_type, m_condition);
580 #else
581             masm->m_assembler.linkJump(m_label, label.m_label);
582 #endif
583         }
584
585         bool isSet() const { return m_label.isSet(); }
586
587     private:
588         AssemblerLabel m_label;
589 #if CPU(ARM_THUMB2)
590         ARMv7Assembler::JumpType m_type;
591         ARMv7Assembler::Condition m_condition;
592 #endif
593 #if CPU(SH4)
594         SH4Assembler::JumpType m_type;
595 #endif
596     };
597
598     struct PatchableJump {
599         PatchableJump()
600         {
601         }
602
603         explicit PatchableJump(Jump jump)
604             : m_jump(jump)
605         {
606         }
607
608         operator Jump&() { return m_jump; }
609
610         Jump m_jump;
611     };
612
613     // JumpList:
614     //
615     // A JumpList is a set of Jump objects.
616     // All jumps in the set will be linked to the same destination.
617     class JumpList {
618         friend class LinkBuffer;
619
620     public:
621         typedef Vector<Jump, 2> JumpVector;
622         
623         JumpList() { }
624         
625         JumpList(Jump jump)
626         {
627             append(jump);
628         }
629
630         void link(AbstractMacroAssembler<AssemblerType>* masm)
631         {
632             size_t size = m_jumps.size();
633             for (size_t i = 0; i < size; ++i)
634                 m_jumps[i].link(masm);
635             m_jumps.clear();
636         }
637         
638         void linkTo(Label label, AbstractMacroAssembler<AssemblerType>* masm)
639         {
640             size_t size = m_jumps.size();
641             for (size_t i = 0; i < size; ++i)
642                 m_jumps[i].linkTo(label, masm);
643             m_jumps.clear();
644         }
645         
646         void append(Jump jump)
647         {
648             m_jumps.append(jump);
649         }
650         
651         void append(const JumpList& other)
652         {
653             m_jumps.append(other.m_jumps.begin(), other.m_jumps.size());
654         }
655
656         bool empty()
657         {
658             return !m_jumps.size();
659         }
660         
661         void clear()
662         {
663             m_jumps.clear();
664         }
665         
666         const JumpVector& jumps() const { return m_jumps; }
667
668     private:
669         JumpVector m_jumps;
670     };
671
672
673     // Section 3: Misc admin methods
674 #if ENABLE(DFG_JIT)
675     Label labelIgnoringWatchpoints()
676     {
677         Label result;
678         result.m_label = m_assembler.labelIgnoringWatchpoints();
679         return result;
680     }
681 #else
682     Label labelIgnoringWatchpoints()
683     {
684         return label();
685     }
686 #endif
687     
688     Label label()
689     {
690         return Label(this);
691     }
692     
693     void padBeforePatch()
694     {
695         // Rely on the fact that asking for a label already does the padding.
696         (void)label();
697     }
698     
699     Label watchpointLabel()
700     {
701         Label result;
702         result.m_label = m_assembler.labelForWatchpoint();
703         return result;
704     }
705     
706     Label align()
707     {
708         m_assembler.align(16);
709         return Label(this);
710     }
711
712 #if ENABLE(DFG_REGISTER_ALLOCATION_VALIDATION)
713     class RegisterAllocationOffset {
714     public:
715         RegisterAllocationOffset(unsigned offset)
716             : m_offset(offset)
717         {
718         }
719
720         void check(unsigned low, unsigned high)
721         {
722             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);
723         }
724
725     private:
726         unsigned m_offset;
727     };
728
729     void addRegisterAllocationAtOffset(unsigned offset)
730     {
731         m_registerAllocationForOffsets.append(RegisterAllocationOffset(offset));
732     }
733
734     void clearRegisterAllocationOffsets()
735     {
736         m_registerAllocationForOffsets.clear();
737     }
738
739     void checkRegisterAllocationAgainstBranchRange(unsigned offset1, unsigned offset2)
740     {
741         if (offset1 > offset2)
742             std::swap(offset1, offset2);
743
744         size_t size = m_registerAllocationForOffsets.size();
745         for (size_t i = 0; i < size; ++i)
746             m_registerAllocationForOffsets[i].check(offset1, offset2);
747     }
748 #endif
749
750     template<typename T, typename U>
751     static ptrdiff_t differenceBetween(T from, U to)
752     {
753         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label);
754     }
755
756     static ptrdiff_t differenceBetweenCodePtr(const MacroAssemblerCodePtr& a, const MacroAssemblerCodePtr& b)
757     {
758         return reinterpret_cast<ptrdiff_t>(b.executableAddress()) - reinterpret_cast<ptrdiff_t>(a.executableAddress());
759     }
760
761     unsigned debugOffset() { return m_assembler.debugOffset(); }
762
763     ALWAYS_INLINE static void cacheFlush(void* code, size_t size)
764     {
765         AssemblerType::cacheFlush(code, size);
766     }
767 protected:
768     AbstractMacroAssembler()
769         : m_randomSource(cryptographicallyRandomNumber())
770     {
771     }
772
773     AssemblerType m_assembler;
774     
775     uint32_t random()
776     {
777         return m_randomSource.getUint32();
778     }
779
780     WeakRandom m_randomSource;
781
782 #if ENABLE(DFG_REGISTER_ALLOCATION_VALIDATION)
783     Vector<RegisterAllocationOffset, 10> m_registerAllocationForOffsets;
784 #endif
785
786 #if ENABLE(JIT_CONSTANT_BLINDING)
787     static bool scratchRegisterForBlinding() { return false; }
788     static bool shouldBlindForSpecificArch(uint32_t) { return true; }
789     static bool shouldBlindForSpecificArch(uint64_t) { return true; }
790 #endif
791
792     friend class LinkBuffer;
793     friend class RepatchBuffer;
794
795     static void linkJump(void* code, Jump jump, CodeLocationLabel target)
796     {
797         AssemblerType::linkJump(code, jump.m_label, target.dataLocation());
798     }
799
800     static void linkPointer(void* code, AssemblerLabel label, void* value)
801     {
802         AssemblerType::linkPointer(code, label, value);
803     }
804
805     static void* getLinkerAddress(void* code, AssemblerLabel label)
806     {
807         return AssemblerType::getRelocatedAddress(code, label);
808     }
809
810     static unsigned getLinkerCallReturnOffset(Call call)
811     {
812         return AssemblerType::getCallReturnOffset(call.m_label);
813     }
814
815     static void repatchJump(CodeLocationJump jump, CodeLocationLabel destination)
816     {
817         AssemblerType::relinkJump(jump.dataLocation(), destination.dataLocation());
818     }
819
820     static void repatchNearCall(CodeLocationNearCall nearCall, CodeLocationLabel destination)
821     {
822         AssemblerType::relinkCall(nearCall.dataLocation(), destination.executableAddress());
823     }
824
825     static void repatchCompact(CodeLocationDataLabelCompact dataLabelCompact, int32_t value)
826     {
827         AssemblerType::repatchCompact(dataLabelCompact.dataLocation(), value);
828     }
829     
830     static void repatchInt32(CodeLocationDataLabel32 dataLabel32, int32_t value)
831     {
832         AssemblerType::repatchInt32(dataLabel32.dataLocation(), value);
833     }
834
835     static void repatchPointer(CodeLocationDataLabelPtr dataLabelPtr, void* value)
836     {
837         AssemblerType::repatchPointer(dataLabelPtr.dataLocation(), value);
838     }
839     
840     static void* readPointer(CodeLocationDataLabelPtr dataLabelPtr)
841     {
842         return AssemblerType::readPointer(dataLabelPtr.dataLocation());
843     }
844     
845     static void replaceWithLoad(CodeLocationConvertibleLoad label)
846     {
847         AssemblerType::replaceWithLoad(label.dataLocation());
848     }
849     
850     static void replaceWithAddressComputation(CodeLocationConvertibleLoad label)
851     {
852         AssemblerType::replaceWithAddressComputation(label.dataLocation());
853     }
854 };
855
856 } // namespace JSC
857
858 #endif // ENABLE(ASSEMBLER)
859
860 #endif // AbstractMacroAssembler_h