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