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