Imported Upstream version 1.0.0
[platform/upstream/js.git] / js / src / assembler / assembler / AbstractMacroAssembler.h
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  * vim: set ts=8 sw=4 et tw=79:
3  *
4  * ***** BEGIN LICENSE BLOCK *****
5  * Copyright (C) 2008 Apple Inc. All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
20  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
24  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
27  * 
28  * ***** END LICENSE BLOCK ***** */
29
30 #ifndef AbstractMacroAssembler_h
31 #define AbstractMacroAssembler_h
32
33 #include "assembler/wtf/Platform.h"
34 #include "assembler/assembler/MacroAssemblerCodeRef.h"
35 #include "assembler/assembler/CodeLocation.h"
36 #include "jsstdint.h"
37
38 #if ENABLE_ASSEMBLER
39
40 namespace JSC {
41
42 class LinkBuffer;
43 class RepatchBuffer;
44
45 template <class AssemblerType>
46 class AbstractMacroAssembler {
47 public:
48     typedef AssemblerType AssemblerType_T;
49
50     typedef MacroAssemblerCodePtr CodePtr;
51     typedef MacroAssemblerCodeRef CodeRef;
52
53     class Jump;
54
55     typedef typename AssemblerType::RegisterID RegisterID;
56     typedef typename AssemblerType::FPRegisterID FPRegisterID;
57     typedef typename AssemblerType::JmpSrc JmpSrc;
58     typedef typename AssemblerType::JmpDst JmpDst;
59
60 #ifdef DEBUG
61     void setSpewPath(bool isOOLPath)
62     {
63         m_assembler.isOOLPath = isOOLPath;
64     }
65 #endif
66
67     // Section 1: MacroAssembler operand types
68     //
69     // The following types are used as operands to MacroAssembler operations,
70     // describing immediate  and memory operands to the instructions to be planted.
71
72
73     enum Scale {
74         TimesOne,
75         TimesTwo,
76         TimesFour,
77         TimesEight
78     };
79
80     // Address:
81     //
82     // Describes a simple base-offset address.
83     struct Address {
84         explicit Address() {}
85
86         explicit Address(RegisterID base, int32_t offset = 0)
87             : base(base)
88             , offset(offset)
89         {
90         }
91
92         RegisterID base;
93         int32_t offset;
94     };
95
96     struct ExtendedAddress {
97         explicit ExtendedAddress(RegisterID base, intptr_t offset = 0)
98             : base(base)
99             , offset(offset)
100         {
101         }
102         
103         RegisterID base;
104         intptr_t offset;
105     };
106
107     // ImplicitAddress:
108     //
109     // This class is used for explicit 'load' and 'store' operations
110     // (as opposed to situations in which a memory operand is provided
111     // to a generic operation, such as an integer arithmetic instruction).
112     //
113     // In the case of a load (or store) operation we want to permit
114     // addresses to be implicitly constructed, e.g. the two calls:
115     //
116     //     load32(Address(addrReg), destReg);
117     //     load32(addrReg, destReg);
118     //
119     // Are equivalent, and the explicit wrapping of the Address in the former
120     // is unnecessary.
121     struct ImplicitAddress {
122         ImplicitAddress(RegisterID base)
123             : base(base)
124             , offset(0)
125         {
126         }
127
128         ImplicitAddress(Address address)
129             : base(address.base)
130             , offset(address.offset)
131         {
132         }
133
134         RegisterID base;
135         int32_t offset;
136     };
137
138     // BaseIndex:
139     //
140     // Describes a complex addressing mode.
141     struct BaseIndex {
142         BaseIndex(RegisterID base, RegisterID index, Scale scale, int32_t offset = 0)
143             : base(base)
144             , index(index)
145             , scale(scale)
146             , offset(offset)
147         {
148         }
149
150         RegisterID base;
151         RegisterID index;
152         Scale scale;
153         int32_t offset;
154     };
155
156     // AbsoluteAddress:
157     //
158     // Describes an memory operand given by a pointer.  For regular load & store
159     // operations an unwrapped void* will be used, rather than using this.
160     struct AbsoluteAddress {
161         explicit AbsoluteAddress(void* ptr)
162             : m_ptr(ptr)
163         {
164         }
165
166         void* m_ptr;
167     };
168
169     // ImmPtr:
170     //
171     // A pointer sized immediate operand to an instruction - this is wrapped
172     // in a class requiring explicit construction in order to differentiate
173     // from pointers used as absolute addresses to memory operations
174     struct ImmPtr {
175         explicit ImmPtr(const void* value)
176             : m_value(value)
177         {
178         }
179
180         intptr_t asIntptr()
181         {
182             return reinterpret_cast<intptr_t>(m_value);
183         }
184
185         const void* m_value;
186     };
187
188     // Imm32:
189     //
190     // A 32bit immediate operand to an instruction - this is wrapped in a
191     // class requiring explicit construction in order to prevent RegisterIDs
192     // (which are implemented as an enum) from accidentally being passed as
193     // immediate values.
194     struct Imm32 {
195         explicit Imm32(int32_t value)
196             : m_value(value)
197 #if WTF_CPU_ARM || WTF_CPU_MIPS
198             , m_isPointer(false)
199 #endif
200         {
201         }
202
203 #if !WTF_CPU_X86_64
204         explicit Imm32(ImmPtr ptr)
205             : m_value(ptr.asIntptr())
206 #if WTF_CPU_ARM || WTF_CPU_MIPS
207             , m_isPointer(true)
208 #endif
209         {
210         }
211 #endif
212
213         int32_t m_value;
214 #if WTF_CPU_ARM || WTF_CPU_MIPS
215         // We rely on being able to regenerate code to recover exception handling
216         // information.  Since ARMv7 supports 16-bit immediates there is a danger
217         // that if pointer values change the layout of the generated code will change.
218         // To avoid this problem, always generate pointers (and thus Imm32s constructed
219         // from ImmPtrs) with a code sequence that is able  to represent  any pointer
220         // value - don't use a more compact form in these cases.
221         // Same for MIPS.
222         bool m_isPointer;
223 #endif
224     };
225
226     struct ImmDouble {
227         union {
228             struct {
229 #if WTF_CPU_BIG_ENDIAN || WTF_CPU_MIDDLE_ENDIAN
230                 uint32 msb, lsb;
231 #else
232                 uint32 lsb, msb;
233 #endif
234             } s;
235             uint64_t u64;
236             double d;
237         } u;
238
239         explicit ImmDouble(double d) {
240             u.d = d;
241         }
242     };
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 isUsed() const { return m_label.isUsed(); }
275         void used() { m_label.used(); }
276         bool isValid() const { return m_label.isValid(); }
277     private:
278         JmpDst m_label;
279     };
280
281     // DataLabelPtr:
282     //
283     // A DataLabelPtr is used to refer to a location in the code containing a pointer to be
284     // patched after the code has been generated.
285     class DataLabelPtr {
286         template<class TemplateAssemblerType>
287         friend class AbstractMacroAssembler;
288         friend class LinkBuffer;
289     public:
290         DataLabelPtr()
291         {
292         }
293
294         DataLabelPtr(AbstractMacroAssembler<AssemblerType>* masm)
295             : m_label(masm->m_assembler.label())
296         {
297         }
298         
299     private:
300         JmpDst m_label;
301     };
302
303     // DataLabel32:
304     //
305     // A DataLabel32 is used to refer to a location in the code containing a
306     // 32-bit constant to be 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     private:
322         JmpDst m_label;
323     };
324
325     // Call:
326     //
327     // A Call object is a reference to a call instruction that has been planted
328     // into the code buffer - it is typically used to link the call, setting the
329     // relative offset such that when executed it will call to the desired
330     // destination.
331     class Call {
332         template<class TemplateAssemblerType>
333         friend class AbstractMacroAssembler;
334
335     public:
336         enum Flags {
337             None = 0x0,
338             Linkable = 0x1,
339             Near = 0x2,
340             LinkableNear = 0x3
341         };
342
343         Call()
344             : m_flags(None)
345         {
346         }
347         
348         Call(JmpSrc jmp, Flags flags)
349             : m_jmp(jmp)
350             , m_flags(flags)
351         {
352         }
353
354         bool isFlagSet(Flags flag)
355         {
356             return !!(m_flags & flag);
357         }
358
359         static Call fromTailJump(Jump jump)
360         {
361             return Call(jump.m_jmp, Linkable);
362         }
363
364         JmpSrc m_jmp;
365     private:
366         Flags m_flags;
367     };
368
369     // Jump:
370     //
371     // A jump object is a reference to a jump instruction that has been planted
372     // into the code buffer - it is typically used to link the jump, setting the
373     // relative offset such that when executed it will jump to the desired
374     // destination.
375     class Jump {
376         template<class TemplateAssemblerType>
377         friend class AbstractMacroAssembler;
378         friend class Call;
379         friend class LinkBuffer;
380     public:
381         Jump()
382         {
383         }
384         
385         Jump(JmpSrc jmp)    
386             : m_jmp(jmp)
387         {
388         }
389         
390         void link(AbstractMacroAssembler<AssemblerType>* masm)
391         {
392             masm->m_assembler.linkJump(m_jmp, masm->m_assembler.label());
393         }
394         
395         void linkTo(Label label, AbstractMacroAssembler<AssemblerType>* masm)
396         {
397             masm->m_assembler.linkJump(m_jmp, label.m_label);
398         }
399
400     private:
401         JmpSrc m_jmp;
402     };
403
404     // JumpList:
405     //
406     // A JumpList is a set of Jump objects.
407     // All jumps in the set will be linked to the same destination.
408     class JumpList {
409         friend class LinkBuffer;
410
411     public:
412         typedef js::Vector<Jump, 16 ,js::SystemAllocPolicy > JumpVector;
413
414         void link(AbstractMacroAssembler<AssemblerType>* masm)
415         {
416             size_t size = m_jumps.length();
417             for (size_t i = 0; i < size; ++i)
418                 m_jumps[i].link(masm);
419             m_jumps.clear();
420         }
421         
422         void linkTo(Label label, AbstractMacroAssembler<AssemblerType>* masm)
423         {
424             size_t size = m_jumps.length();
425             for (size_t i = 0; i < size; ++i)
426                 m_jumps[i].linkTo(label, masm);
427             m_jumps.clear();
428         }
429         
430         void append(Jump jump)
431         {
432             m_jumps.append(jump);
433         }
434         
435         void append(JumpList& other)
436         {
437             m_jumps.append(other.m_jumps.begin(), other.m_jumps.length());
438         }
439
440         bool empty()
441         {
442             return !m_jumps.length();
443         }
444         
445         const JumpVector& jumps() { return m_jumps; }
446
447     private:
448         JumpVector m_jumps;
449     };
450
451
452     // Section 3: Misc admin methods
453
454     static CodePtr trampolineAt(CodeRef ref, Label label)
455     {
456         return CodePtr(AssemblerType::getRelocatedAddress(ref.m_code.dataLocation(), label.m_label));
457     }
458
459     size_t size()
460     {
461         return m_assembler.size();
462     }
463
464     unsigned char *buffer()
465     {
466         return m_assembler.buffer();
467     }
468
469     bool oom()
470     {
471         return m_assembler.oom();
472     }
473
474     void* executableCopy(void* buffer)
475     {
476         return m_assembler.executableCopy(buffer);
477     }
478
479     Label label()
480     {
481         return Label(this);
482     }
483
484     DataLabel32 dataLabel32()
485     {
486         return DataLabel32(this);
487     }
488     
489     Label align()
490     {
491         m_assembler.align(16);
492         return Label(this);
493     }
494
495     ptrdiff_t differenceBetween(Label from, Jump to)
496     {
497         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp);
498     }
499
500     ptrdiff_t differenceBetween(Label from, Call to)
501     {
502         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp);
503     }
504
505     ptrdiff_t differenceBetween(Label from, Label to)
506     {
507         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label);
508     }
509
510     ptrdiff_t differenceBetween(Label from, DataLabelPtr to)
511     {
512         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label);
513     }
514
515     ptrdiff_t differenceBetween(Label from, DataLabel32 to)
516     {
517         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label);
518     }
519
520     ptrdiff_t differenceBetween(DataLabel32 from, Label to)
521     {
522         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label);
523     }
524
525     ptrdiff_t differenceBetween(DataLabelPtr from, Jump to)
526     {
527         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp);
528     }
529
530     ptrdiff_t differenceBetween(DataLabelPtr from, DataLabelPtr to)
531     {
532         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label);
533     }
534
535     ptrdiff_t differenceBetween(DataLabelPtr from, Call to)
536     {
537         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp);
538     }
539
540 protected:
541     AssemblerType m_assembler;
542
543     friend class LinkBuffer;
544     friend class RepatchBuffer;
545
546     static void linkJump(void* code, Jump jump, CodeLocationLabel target)
547     {
548         AssemblerType::linkJump(code, jump.m_jmp, target.dataLocation());
549     }
550
551     static void linkPointer(void* code, typename AssemblerType::JmpDst label, void* value)
552     {
553         AssemblerType::linkPointer(code, label, value);
554     }
555
556     static void* getLinkerAddress(void* code, typename AssemblerType::JmpSrc label)
557     {
558         return AssemblerType::getRelocatedAddress(code, label);
559     }
560
561     static void* getLinkerAddress(void* code, typename AssemblerType::JmpDst label)
562     {
563         return AssemblerType::getRelocatedAddress(code, label);
564     }
565
566     static unsigned getLinkerCallReturnOffset(Call call)
567     {
568         return AssemblerType::getCallReturnOffset(call.m_jmp);
569     }
570
571     static void repatchJump(CodeLocationJump jump, CodeLocationLabel destination)
572     {
573         AssemblerType::relinkJump(jump.dataLocation(), destination.dataLocation());
574     }
575
576     static bool canRepatchJump(CodeLocationJump jump, CodeLocationLabel destination)
577     {
578         return AssemblerType::canRelinkJump(jump.dataLocation(), destination.dataLocation());
579     }
580
581     static void repatchNearCall(CodeLocationNearCall nearCall, CodeLocationLabel destination)
582     {
583         AssemblerType::relinkCall(nearCall.dataLocation(), destination.executableAddress());
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 repatchLoadPtrToLEA(CodeLocationInstruction instruction)
597     {
598         AssemblerType::repatchLoadPtrToLEA(instruction.dataLocation());
599     }
600
601     static void repatchLEAToLoadPtr(CodeLocationInstruction instruction)
602     {
603         AssemblerType::repatchLEAToLoadPtr(instruction.dataLocation());
604     }
605 };
606
607 } // namespace JSC
608
609 #endif // ENABLE(ASSEMBLER)
610
611 #endif // AbstractMacroAssembler_h