• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
38 namespace JSC {
39 
40 class LinkBuffer;
41 class RepatchBuffer;
42 
43 template <class AssemblerType>
44 class AbstractMacroAssembler {
45 public:
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)
baseAddress77             : 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 {
ImplicitAddressImplicitAddress101         ImplicitAddress(RegisterID base)
102             : base(base)
103             , offset(0)
104         {
105         }
106 
ImplicitAddressImplicitAddress107         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)
baseBaseIndex122             : 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 {
AbsoluteAddressAbsoluteAddress140         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 {
ImmPtrImmPtr154         explicit ImmPtr(void* value)
155             : m_value(value)
156         {
157         }
158 
asIntptrImmPtr159         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 {
Imm32Imm32174         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)
Imm32Imm32183         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:
Label()225         Label()
226         {
227         }
228 
Label(AbstractMacroAssembler<AssemblerType> * masm)229         Label(AbstractMacroAssembler<AssemblerType>* masm)
230             : m_label(masm->m_assembler.label())
231         {
232         }
233 
isUsed()234         bool isUsed() const { return m_label.isUsed(); }
used()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:
DataLabelPtr()249         DataLabelPtr()
250         {
251         }
252 
DataLabelPtr(AbstractMacroAssembler<AssemblerType> * masm)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:
DataLabel32()271         DataLabel32()
272         {
273         }
274 
DataLabel32(AbstractMacroAssembler<AssemblerType> * masm)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 
Call()302         Call()
303             : m_flags(None)
304         {
305         }
306 
Call(JmpSrc jmp,Flags flags)307         Call(JmpSrc jmp, Flags flags)
308             : m_jmp(jmp)
309             , m_flags(flags)
310         {
311         }
312 
isFlagSet(Flags flag)313         bool isFlagSet(Flags flag)
314         {
315             return m_flags & flag;
316         }
317 
fromTailJump(Jump jump)318         static Call fromTailJump(Jump jump)
319         {
320             return Call(jump.m_jmp, Linkable);
321         }
322 
enableLatePatch()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:
Jump()345         Jump()
346         {
347         }
348 
Jump(JmpSrc jmp)349         Jump(JmpSrc jmp)
350             : m_jmp(jmp)
351         {
352         }
353 
link(AbstractMacroAssembler<AssemblerType> * masm)354         void link(AbstractMacroAssembler<AssemblerType>* masm)
355         {
356             masm->m_assembler.linkJump(m_jmp, masm->m_assembler.label());
357         }
358 
linkTo(Label label,AbstractMacroAssembler<AssemblerType> * masm)359         void linkTo(Label label, AbstractMacroAssembler<AssemblerType>* masm)
360         {
361             masm->m_assembler.linkJump(m_jmp, label.m_label);
362         }
363 
enableLatePatch()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 
link(AbstractMacroAssembler<AssemblerType> * masm)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 
linkTo(Label label,AbstractMacroAssembler<AssemblerType> * masm)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 
append(Jump jump)399         void append(Jump jump)
400         {
401             m_jumps.append(jump);
402         }
403 
append(JumpList & other)404         void append(JumpList& other)
405         {
406             m_jumps.append(other.m_jumps.begin(), other.m_jumps.size());
407         }
408 
empty()409         bool empty()
410         {
411             return !m_jumps.size();
412         }
413 
jumps()414         const JumpVector& jumps() { return m_jumps; }
415 
416     private:
417         JumpVector m_jumps;
418     };
419 
420 
421     // Section 3: Misc admin methods
422 
trampolineAt(CodeRef ref,Label label)423     static CodePtr trampolineAt(CodeRef ref, Label label)
424     {
425         return CodePtr(AssemblerType::getRelocatedAddress(ref.m_code.dataLocation(), label.m_label));
426     }
427 
size()428     size_t size()
429     {
430         return m_assembler.size();
431     }
432 
label()433     Label label()
434     {
435         return Label(this);
436     }
437 
align()438     Label align()
439     {
440         m_assembler.align(16);
441         return Label(this);
442     }
443 
differenceBetween(Label from,Jump to)444     ptrdiff_t differenceBetween(Label from, Jump to)
445     {
446         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp);
447     }
448 
differenceBetween(Label from,Call to)449     ptrdiff_t differenceBetween(Label from, Call to)
450     {
451         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp);
452     }
453 
differenceBetween(Label from,Label to)454     ptrdiff_t differenceBetween(Label from, Label to)
455     {
456         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label);
457     }
458 
differenceBetween(Label from,DataLabelPtr to)459     ptrdiff_t differenceBetween(Label from, DataLabelPtr to)
460     {
461         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label);
462     }
463 
differenceBetween(Label from,DataLabel32 to)464     ptrdiff_t differenceBetween(Label from, DataLabel32 to)
465     {
466         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label);
467     }
468 
differenceBetween(DataLabelPtr from,Jump to)469     ptrdiff_t differenceBetween(DataLabelPtr from, Jump to)
470     {
471         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp);
472     }
473 
differenceBetween(DataLabelPtr from,DataLabelPtr to)474     ptrdiff_t differenceBetween(DataLabelPtr from, DataLabelPtr to)
475     {
476         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label);
477     }
478 
differenceBetween(DataLabelPtr from,Call to)479     ptrdiff_t differenceBetween(DataLabelPtr from, Call to)
480     {
481         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp);
482     }
483 
484 protected:
485     AssemblerType m_assembler;
486 
487     friend class LinkBuffer;
488     friend class RepatchBuffer;
489 
linkJump(void * code,Jump jump,CodeLocationLabel target)490     static void linkJump(void* code, Jump jump, CodeLocationLabel target)
491     {
492         AssemblerType::linkJump(code, jump.m_jmp, target.dataLocation());
493     }
494 
linkPointer(void * code,typename AssemblerType::JmpDst label,void * value)495     static void linkPointer(void* code, typename AssemblerType::JmpDst label, void* value)
496     {
497         AssemblerType::linkPointer(code, label, value);
498     }
499 
getLinkerAddress(void * code,typename AssemblerType::JmpSrc label)500     static void* getLinkerAddress(void* code, typename AssemblerType::JmpSrc label)
501     {
502         return AssemblerType::getRelocatedAddress(code, label);
503     }
504 
getLinkerAddress(void * code,typename AssemblerType::JmpDst label)505     static void* getLinkerAddress(void* code, typename AssemblerType::JmpDst label)
506     {
507         return AssemblerType::getRelocatedAddress(code, label);
508     }
509 
getLinkerCallReturnOffset(Call call)510     static unsigned getLinkerCallReturnOffset(Call call)
511     {
512         return AssemblerType::getCallReturnOffset(call.m_jmp);
513     }
514 
repatchJump(CodeLocationJump jump,CodeLocationLabel destination)515     static void repatchJump(CodeLocationJump jump, CodeLocationLabel destination)
516     {
517         AssemblerType::relinkJump(jump.dataLocation(), destination.dataLocation());
518     }
519 
repatchNearCall(CodeLocationNearCall nearCall,CodeLocationLabel destination)520     static void repatchNearCall(CodeLocationNearCall nearCall, CodeLocationLabel destination)
521     {
522         AssemblerType::relinkCall(nearCall.dataLocation(), destination.executableAddress());
523     }
524 
repatchInt32(CodeLocationDataLabel32 dataLabel32,int32_t value)525     static void repatchInt32(CodeLocationDataLabel32 dataLabel32, int32_t value)
526     {
527         AssemblerType::repatchInt32(dataLabel32.dataLocation(), value);
528     }
529 
repatchPointer(CodeLocationDataLabelPtr dataLabelPtr,void * value)530     static void repatchPointer(CodeLocationDataLabelPtr dataLabelPtr, void* value)
531     {
532         AssemblerType::repatchPointer(dataLabelPtr.dataLocation(), value);
533     }
534 
repatchLoadPtrToLEA(CodeLocationInstruction instruction)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