a0039cb526dd710ec5de093f6bb159382e4953dc
[WebKit-https.git] / Source / JavaScriptCore / assembler / AbstractMacroAssembler.h
1 /*
2  * Copyright (C) 2008 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 class LinkBuffer;
50 class RepatchBuffer;
51 namespace DFG {
52 class CorrectableJumpPoint;
53 }
54
55 template <class AssemblerType>
56 class AbstractMacroAssembler {
57 public:
58     friend class JITWriteBarrierBase;
59     typedef AssemblerType AssemblerType_T;
60
61     typedef MacroAssemblerCodePtr CodePtr;
62     typedef MacroAssemblerCodeRef CodeRef;
63
64     class Jump;
65
66     typedef typename AssemblerType::RegisterID RegisterID;
67
68     // Section 1: MacroAssembler operand types
69     //
70     // The following types are used as operands to MacroAssembler operations,
71     // describing immediate  and memory operands to the instructions to be planted.
72
73
74     enum Scale {
75         TimesOne,
76         TimesTwo,
77         TimesFour,
78         TimesEight,
79     };
80
81     // Address:
82     //
83     // Describes a simple base-offset address.
84     struct Address {
85         explicit Address(RegisterID base, int32_t offset = 0)
86             : base(base)
87             , offset(offset)
88         {
89         }
90
91         RegisterID base;
92         int32_t offset;
93     };
94
95     struct ExtendedAddress {
96         explicit ExtendedAddress(RegisterID base, intptr_t offset = 0)
97             : base(base)
98             , offset(offset)
99         {
100         }
101         
102         RegisterID base;
103         intptr_t offset;
104     };
105
106     // ImplicitAddress:
107     //
108     // This class is used for explicit 'load' and 'store' operations
109     // (as opposed to situations in which a memory operand is provided
110     // to a generic operation, such as an integer arithmetic instruction).
111     //
112     // In the case of a load (or store) operation we want to permit
113     // addresses to be implicitly constructed, e.g. the two calls:
114     //
115     //     load32(Address(addrReg), destReg);
116     //     load32(addrReg, destReg);
117     //
118     // Are equivalent, and the explicit wrapping of the Address in the former
119     // is unnecessary.
120     struct ImplicitAddress {
121         ImplicitAddress(RegisterID base)
122             : base(base)
123             , offset(0)
124         {
125         }
126
127         ImplicitAddress(Address address)
128             : base(address.base)
129             , offset(address.offset)
130         {
131         }
132
133         RegisterID base;
134         int32_t offset;
135     };
136
137     // BaseIndex:
138     //
139     // Describes a complex addressing mode.
140     struct BaseIndex {
141         BaseIndex(RegisterID base, RegisterID index, Scale scale, int32_t offset = 0)
142             : base(base)
143             , index(index)
144             , scale(scale)
145             , offset(offset)
146         {
147         }
148
149         RegisterID base;
150         RegisterID index;
151         Scale scale;
152         int32_t offset;
153     };
154
155     // AbsoluteAddress:
156     //
157     // Describes an memory operand given by a pointer.  For regular load & store
158     // operations an unwrapped void* will be used, rather than using this.
159     struct AbsoluteAddress {
160         explicit AbsoluteAddress(const void* ptr)
161             : m_ptr(ptr)
162         {
163         }
164
165         const void* m_ptr;
166     };
167
168     // TrustedImmPtr:
169     //
170     // A pointer sized immediate operand to an instruction - this is wrapped
171     // in a class requiring explicit construction in order to differentiate
172     // from pointers used as absolute addresses to memory operations
173     struct TrustedImmPtr {
174         TrustedImmPtr() { }
175         
176         explicit TrustedImmPtr(const void* value)
177             : m_value(value)
178         {
179         }
180         
181         // This is only here so that TrustedImmPtr(0) does not confuse the C++
182         // overload handling rules.
183         explicit TrustedImmPtr(int value)
184             : m_value(0)
185         {
186             ASSERT_UNUSED(value, !value);
187         }
188
189         explicit TrustedImmPtr(size_t value)
190             : m_value(reinterpret_cast<void*>(value))
191         {
192         }
193
194         intptr_t asIntptr()
195         {
196             return reinterpret_cast<intptr_t>(m_value);
197         }
198
199         const void* m_value;
200     };
201
202     struct ImmPtr : 
203 #if ENABLE(JIT_CONSTANT_BLINDING)
204         private TrustedImmPtr 
205 #else
206         public TrustedImmPtr
207 #endif
208     {
209         explicit ImmPtr(const void* value)
210             : TrustedImmPtr(value)
211         {
212         }
213
214         TrustedImmPtr asTrustedImmPtr() { return *this; }
215     };
216
217     // TrustedImm32:
218     //
219     // A 32bit immediate operand to an instruction - this is wrapped in a
220     // class requiring explicit construction in order to prevent RegisterIDs
221     // (which are implemented as an enum) from accidentally being passed as
222     // immediate values.
223     struct TrustedImm32 {
224         TrustedImm32() { }
225         
226         explicit TrustedImm32(int32_t value)
227             : m_value(value)
228         {
229         }
230
231 #if !CPU(X86_64)
232         explicit TrustedImm32(TrustedImmPtr ptr)
233             : m_value(ptr.asIntptr())
234         {
235         }
236 #endif
237
238         int32_t m_value;
239     };
240
241
242     struct Imm32 : 
243 #if ENABLE(JIT_CONSTANT_BLINDING)
244         private TrustedImm32 
245 #else
246         public TrustedImm32
247 #endif
248     {
249         explicit Imm32(int32_t value)
250             : TrustedImm32(value)
251         {
252         }
253 #if !CPU(X86_64)
254         explicit Imm32(TrustedImmPtr ptr)
255             : TrustedImm32(ptr)
256         {
257         }
258 #endif
259         const TrustedImm32& asTrustedImm32() const { return *this; }
260
261     };
262     
263     // Section 2: MacroAssembler code buffer handles
264     //
265     // The following types are used to reference items in the code buffer
266     // during JIT code generation.  For example, the type Jump is used to
267     // track the location of a jump instruction so that it may later be
268     // linked to a label marking its destination.
269
270
271     // Label:
272     //
273     // A Label records a point in the generated instruction stream, typically such that
274     // it may be used as a destination for a jump.
275     class Label {
276         template<class TemplateAssemblerType>
277         friend class AbstractMacroAssembler;
278         friend class DFG::CorrectableJumpPoint;
279         friend class Jump;
280         friend class MacroAssemblerCodeRef;
281         friend class LinkBuffer;
282
283     public:
284         Label()
285         {
286         }
287
288         Label(AbstractMacroAssembler<AssemblerType>* masm)
289             : m_label(masm->m_assembler.label())
290         {
291         }
292         
293         bool isSet() const { return m_label.isSet(); }
294     private:
295         AssemblerLabel m_label;
296     };
297
298     // DataLabelPtr:
299     //
300     // A DataLabelPtr is used to refer to a location in the code containing a pointer to be
301     // patched after the code has been generated.
302     class DataLabelPtr {
303         template<class TemplateAssemblerType>
304         friend class AbstractMacroAssembler;
305         friend class LinkBuffer;
306     public:
307         DataLabelPtr()
308         {
309         }
310
311         DataLabelPtr(AbstractMacroAssembler<AssemblerType>* masm)
312             : m_label(masm->m_assembler.label())
313         {
314         }
315         
316         bool isSet() const { return m_label.isSet(); }
317         
318     private:
319         AssemblerLabel m_label;
320     };
321
322     // DataLabel32:
323     //
324     // A DataLabelPtr is used to refer to a location in the code containing a pointer to be
325     // patched after the code has been generated.
326     class DataLabel32 {
327         template<class TemplateAssemblerType>
328         friend class AbstractMacroAssembler;
329         friend class LinkBuffer;
330     public:
331         DataLabel32()
332         {
333         }
334
335         DataLabel32(AbstractMacroAssembler<AssemblerType>* masm)
336             : m_label(masm->m_assembler.label())
337         {
338         }
339
340         AssemblerLabel label() const { return m_label; }
341
342     private:
343         AssemblerLabel m_label;
344     };
345
346     // DataLabelCompact:
347     //
348     // A DataLabelCompact is used to refer to a location in the code containing a
349     // compact immediate to be patched after the code has been generated.
350     class DataLabelCompact {
351         template<class TemplateAssemblerType>
352         friend class AbstractMacroAssembler;
353         friend class LinkBuffer;
354     public:
355         DataLabelCompact()
356         {
357         }
358         
359         DataLabelCompact(AbstractMacroAssembler<AssemblerType>* masm)
360             : m_label(masm->m_assembler.label())
361         {
362         }
363     
364         DataLabelCompact(AssemblerLabel label)
365             : m_label(label)
366         {
367         }
368
369     private:
370         AssemblerLabel m_label;
371     };
372
373     // Call:
374     //
375     // A Call object is a reference to a call instruction that has been planted
376     // into the code buffer - it is typically used to link the call, setting the
377     // relative offset such that when executed it will call to the desired
378     // destination.
379     class Call {
380         template<class TemplateAssemblerType>
381         friend class AbstractMacroAssembler;
382
383     public:
384         enum Flags {
385             None = 0x0,
386             Linkable = 0x1,
387             Near = 0x2,
388             LinkableNear = 0x3,
389         };
390
391         Call()
392             : m_flags(None)
393         {
394         }
395         
396         Call(AssemblerLabel jmp, Flags flags)
397             : m_label(jmp)
398             , m_flags(flags)
399         {
400         }
401
402         bool isFlagSet(Flags flag)
403         {
404             return m_flags & flag;
405         }
406
407         static Call fromTailJump(Jump jump)
408         {
409             return Call(jump.m_label, Linkable);
410         }
411
412         AssemblerLabel m_label;
413     private:
414         Flags m_flags;
415     };
416
417     // Jump:
418     //
419     // A jump object is a reference to a jump instruction that has been planted
420     // into the code buffer - it is typically used to link the jump, setting the
421     // relative offset such that when executed it will jump to the desired
422     // destination.
423     class Jump {
424         template<class TemplateAssemblerType>
425         friend class AbstractMacroAssembler;
426         friend class Call;
427         friend class DFG::CorrectableJumpPoint;
428         friend class LinkBuffer;
429     public:
430         Jump()
431         {
432         }
433         
434 #if CPU(ARM_THUMB2)
435         // Fixme: this information should be stored in the instruction stream, not in the Jump object.
436         Jump(AssemblerLabel jmp, ARMv7Assembler::JumpType type, ARMv7Assembler::Condition condition = ARMv7Assembler::ConditionInvalid)
437             : m_label(jmp)
438             , m_type(type)
439             , m_condition(condition)
440         {
441         }
442 #elif CPU(SH4)
443         Jump(AssemblerLabel jmp, SH4Assembler::JumpType type = SH4Assembler::JumpFar)
444             : m_label(jmp)
445             , m_type(type)
446         {
447         }
448 #else
449         Jump(AssemblerLabel jmp)    
450             : m_label(jmp)
451         {
452         }
453 #endif
454
455         void link(AbstractMacroAssembler<AssemblerType>* masm) const
456         {
457 #if CPU(ARM_THUMB2)
458             masm->m_assembler.linkJump(m_label, masm->m_assembler.label(), m_type, m_condition);
459 #elif CPU(SH4)
460             masm->m_assembler.linkJump(m_label, masm->m_assembler.label(), m_type);
461 #else
462             masm->m_assembler.linkJump(m_label, masm->m_assembler.label());
463 #endif
464         }
465         
466         void linkTo(Label label, AbstractMacroAssembler<AssemblerType>* masm) const
467         {
468 #if CPU(ARM_THUMB2)
469             masm->m_assembler.linkJump(m_label, label.m_label, m_type, m_condition);
470 #else
471             masm->m_assembler.linkJump(m_label, label.m_label);
472 #endif
473         }
474
475         bool isSet() const { return m_label.isSet(); }
476
477     private:
478         AssemblerLabel m_label;
479 #if CPU(ARM_THUMB2)
480         ARMv7Assembler::JumpType m_type;
481         ARMv7Assembler::Condition m_condition;
482 #endif
483 #if CPU(SH4)
484         SH4Assembler::JumpType m_type;
485 #endif
486     };
487
488     struct PatchableJump {
489         PatchableJump()
490         {
491         }
492
493         explicit PatchableJump(Jump jump)
494             : m_jump(jump)
495         {
496         }
497
498         operator Jump&() { return m_jump; }
499
500         Jump m_jump;
501     };
502
503     // JumpList:
504     //
505     // A JumpList is a set of Jump objects.
506     // All jumps in the set will be linked to the same destination.
507     class JumpList {
508         friend class LinkBuffer;
509
510     public:
511         typedef Vector<Jump, 16> JumpVector;
512
513         void link(AbstractMacroAssembler<AssemblerType>* masm)
514         {
515             size_t size = m_jumps.size();
516             for (size_t i = 0; i < size; ++i)
517                 m_jumps[i].link(masm);
518             m_jumps.clear();
519         }
520         
521         void linkTo(Label label, AbstractMacroAssembler<AssemblerType>* masm)
522         {
523             size_t size = m_jumps.size();
524             for (size_t i = 0; i < size; ++i)
525                 m_jumps[i].linkTo(label, masm);
526             m_jumps.clear();
527         }
528         
529         void append(Jump jump)
530         {
531             m_jumps.append(jump);
532         }
533         
534         void append(JumpList& other)
535         {
536             m_jumps.append(other.m_jumps.begin(), other.m_jumps.size());
537         }
538
539         bool empty()
540         {
541             return !m_jumps.size();
542         }
543         
544         void clear()
545         {
546             m_jumps.clear();
547         }
548         
549         const JumpVector& jumps() { return m_jumps; }
550
551     private:
552         JumpVector m_jumps;
553     };
554
555
556     // Section 3: Misc admin methods
557     Label label()
558     {
559         return Label(this);
560     }
561     
562     Label align()
563     {
564         m_assembler.align(16);
565         return Label(this);
566     }
567
568     template<typename T, typename U>
569     static ptrdiff_t differenceBetween(T from, U to)
570     {
571         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label);
572     }
573
574     static ptrdiff_t differenceBetweenCodePtr(const MacroAssemblerCodePtr& a, const MacroAssemblerCodePtr& b)
575     {
576         return reinterpret_cast<ptrdiff_t>(b.executableAddress()) - reinterpret_cast<ptrdiff_t>(a.executableAddress());
577     }
578
579     unsigned debugOffset() { return m_assembler.debugOffset(); }
580
581     ALWAYS_INLINE static void cacheFlush(void* code, size_t size)
582     {
583         AssemblerType::cacheFlush(code, size);
584     }
585 protected:
586     AbstractMacroAssembler()
587         : m_randomSource(cryptographicallyRandomNumber())
588     {
589     }
590
591     AssemblerType m_assembler;
592     
593     uint32_t random()
594     {
595         return m_randomSource.getUint32();
596     }
597
598     WeakRandom m_randomSource;
599
600 #if ENABLE(JIT_CONSTANT_BLINDING)
601     static bool scratchRegisterForBlinding() { return false; }
602     static bool shouldBlindForSpecificArch(uint32_t) { return true; }
603     static bool shouldBlindForSpecificArch(uint64_t) { return true; }
604 #endif
605
606     friend class LinkBuffer;
607     friend class RepatchBuffer;
608
609     static void linkJump(void* code, Jump jump, CodeLocationLabel target)
610     {
611         AssemblerType::linkJump(code, jump.m_label, target.dataLocation());
612     }
613
614     static void linkPointer(void* code, AssemblerLabel label, void* value)
615     {
616         AssemblerType::linkPointer(code, label, value);
617     }
618
619     static void* getLinkerAddress(void* code, AssemblerLabel label)
620     {
621         return AssemblerType::getRelocatedAddress(code, label);
622     }
623
624     static unsigned getLinkerCallReturnOffset(Call call)
625     {
626         return AssemblerType::getCallReturnOffset(call.m_label);
627     }
628
629     static void repatchJump(CodeLocationJump jump, CodeLocationLabel destination)
630     {
631         AssemblerType::relinkJump(jump.dataLocation(), destination.dataLocation());
632     }
633
634     static void repatchNearCall(CodeLocationNearCall nearCall, CodeLocationLabel destination)
635     {
636         AssemblerType::relinkCall(nearCall.dataLocation(), destination.executableAddress());
637     }
638
639     static void repatchCompact(CodeLocationDataLabelCompact dataLabelCompact, int32_t value)
640     {
641         AssemblerType::repatchCompact(dataLabelCompact.dataLocation(), value);
642     }
643     
644     static void repatchInt32(CodeLocationDataLabel32 dataLabel32, int32_t value)
645     {
646         AssemblerType::repatchInt32(dataLabel32.dataLocation(), value);
647     }
648
649     static void repatchPointer(CodeLocationDataLabelPtr dataLabelPtr, void* value)
650     {
651         AssemblerType::repatchPointer(dataLabelPtr.dataLocation(), value);
652     }
653     
654     static void* readPointer(CodeLocationDataLabelPtr dataLabelPtr)
655     {
656         return AssemblerType::readPointer(dataLabelPtr.dataLocation());
657     }
658     
659     static void unreachableForPlatform()
660     {
661 #if COMPILER(CLANG)
662 #pragma clang diagnostic push
663 #pragma clang diagnostic ignored "-Wmissing-noreturn"
664         ASSERT_NOT_REACHED();
665 #pragma clang diagnostic pop
666 #else
667         ASSERT_NOT_REACHED();
668 #endif
669     }
670 };
671
672 } // namespace JSC
673
674 #endif // ENABLE(ASSEMBLER)
675
676 #endif // AbstractMacroAssembler_h