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