• 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 "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     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)
baseAddress74             : 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)
baseExtendedAddress85             : 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 {
ImplicitAddressImplicitAddress109         ImplicitAddress(RegisterID base)
110             : base(base)
111             , offset(0)
112         {
113         }
114 
ImplicitAddressImplicitAddress115         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)
baseBaseIndex130             : 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 {
AbsoluteAddressAbsoluteAddress148         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 {
TrustedImmPtrTrustedImmPtr162         explicit TrustedImmPtr(const void* value)
163             : m_value(value)
164         {
165         }
166 
asIntptrTrustedImmPtr167         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 {
ImmPtrImmPtr176         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 {
TrustedImm32TrustedImm32189         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)
TrustedImm32TrustedImm32198         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 {
Imm32Imm32222         explicit Imm32(int32_t value)
223             : TrustedImm32(value)
224         {
225         }
226 #if !CPU(X86_64)
Imm32Imm32227         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:
Label()254         Label()
255         {
256         }
257 
Label(AbstractMacroAssembler<AssemblerType> * masm)258         Label(AbstractMacroAssembler<AssemblerType>* masm)
259             : m_label(masm->m_assembler.label())
260         {
261         }
262 
isUsed()263         bool isUsed() const { return m_label.isUsed(); }
isSet()264         bool isSet() const { return m_label.isSet(); }
used()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:
DataLabelPtr()279         DataLabelPtr()
280         {
281         }
282 
DataLabelPtr(AbstractMacroAssembler<AssemblerType> * masm)283         DataLabelPtr(AbstractMacroAssembler<AssemblerType>* masm)
284             : m_label(masm->m_assembler.label())
285         {
286         }
287 
isSet()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:
DataLabel32()303         DataLabel32()
304         {
305         }
306 
DataLabel32(AbstractMacroAssembler<AssemblerType> * masm)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 
Call()334         Call()
335             : m_flags(None)
336         {
337         }
338 
Call(JmpSrc jmp,Flags flags)339         Call(JmpSrc jmp, Flags flags)
340             : m_jmp(jmp)
341             , m_flags(flags)
342         {
343         }
344 
isFlagSet(Flags flag)345         bool isFlagSet(Flags flag)
346         {
347             return m_flags & flag;
348         }
349 
fromTailJump(Jump jump)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:
Jump()372         Jump()
373         {
374         }
375 
Jump(JmpSrc jmp)376         Jump(JmpSrc jmp)
377             : m_jmp(jmp)
378         {
379         }
380 
link(AbstractMacroAssembler<AssemblerType> * masm)381         void link(AbstractMacroAssembler<AssemblerType>* masm) const
382         {
383             masm->m_assembler.linkJump(m_jmp, masm->m_assembler.label());
384         }
385 
linkTo(Label label,AbstractMacroAssembler<AssemblerType> * masm)386         void linkTo(Label label, AbstractMacroAssembler<AssemblerType>* masm) const
387         {
388             masm->m_assembler.linkJump(m_jmp, label.m_label);
389         }
390 
isSet()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 
link(AbstractMacroAssembler<AssemblerType> * masm)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 
linkTo(Label label,AbstractMacroAssembler<AssemblerType> * masm)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 
append(Jump jump)423         void append(Jump jump)
424         {
425             m_jumps.append(jump);
426         }
427 
append(JumpList & other)428         void append(JumpList& other)
429         {
430             m_jumps.append(other.m_jumps.begin(), other.m_jumps.size());
431         }
432 
empty()433         bool empty()
434         {
435             return !m_jumps.size();
436         }
437 
clear()438         void clear()
439         {
440             m_jumps.clear();
441         }
442 
jumps()443         const JumpVector& jumps() { return m_jumps; }
444 
445     private:
446         JumpVector m_jumps;
447     };
448 
449 
450     // Section 3: Misc admin methods
size()451     size_t size()
452     {
453         return m_assembler.size();
454     }
455 
label()456     Label label()
457     {
458         return Label(this);
459     }
460 
align()461     Label align()
462     {
463         m_assembler.align(16);
464         return Label(this);
465     }
466 
differenceBetween(Label from,Jump to)467     ptrdiff_t differenceBetween(Label from, Jump to)
468     {
469         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp);
470     }
471 
differenceBetween(Label from,Call to)472     ptrdiff_t differenceBetween(Label from, Call to)
473     {
474         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp);
475     }
476 
differenceBetween(Label from,Label to)477     ptrdiff_t differenceBetween(Label from, Label to)
478     {
479         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label);
480     }
481 
differenceBetween(Label from,DataLabelPtr to)482     ptrdiff_t differenceBetween(Label from, DataLabelPtr to)
483     {
484         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label);
485     }
486 
differenceBetween(Label from,DataLabel32 to)487     ptrdiff_t differenceBetween(Label from, DataLabel32 to)
488     {
489         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label);
490     }
491 
differenceBetween(DataLabelPtr from,Jump to)492     ptrdiff_t differenceBetween(DataLabelPtr from, Jump to)
493     {
494         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_jmp);
495     }
496 
differenceBetween(DataLabelPtr from,DataLabelPtr to)497     ptrdiff_t differenceBetween(DataLabelPtr from, DataLabelPtr to)
498     {
499         return AssemblerType::getDifferenceBetweenLabels(from.m_label, to.m_label);
500     }
501 
differenceBetween(DataLabelPtr from,Call to)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)
rewindToLabel(Label rewindTo)509     void rewindToLabel(Label rewindTo) { m_assembler.rewindToLabel(rewindTo.m_label); }
510 #endif
511 
beginUninterruptedSequence()512     void beginUninterruptedSequence() { }
endUninterruptedSequence()513     void endUninterruptedSequence() { }
514 
515 #ifndef NDEBUG
debugOffset()516     unsigned debugOffset() { return m_assembler.debugOffset(); }
517 #endif
518 
519 protected:
520     AssemblerType m_assembler;
521 
522     friend class LinkBuffer;
523     friend class RepatchBuffer;
524 
linkJump(void * code,Jump jump,CodeLocationLabel target)525     static void linkJump(void* code, Jump jump, CodeLocationLabel target)
526     {
527         AssemblerType::linkJump(code, jump.m_jmp, target.dataLocation());
528     }
529 
linkPointer(void * code,typename AssemblerType::JmpDst label,void * value)530     static void linkPointer(void* code, typename AssemblerType::JmpDst label, void* value)
531     {
532         AssemblerType::linkPointer(code, label, value);
533     }
534 
getLinkerAddress(void * code,typename AssemblerType::JmpSrc label)535     static void* getLinkerAddress(void* code, typename AssemblerType::JmpSrc label)
536     {
537         return AssemblerType::getRelocatedAddress(code, label);
538     }
539 
getLinkerAddress(void * code,typename AssemblerType::JmpDst label)540     static void* getLinkerAddress(void* code, typename AssemblerType::JmpDst label)
541     {
542         return AssemblerType::getRelocatedAddress(code, label);
543     }
544 
getLinkerCallReturnOffset(Call call)545     static unsigned getLinkerCallReturnOffset(Call call)
546     {
547         return AssemblerType::getCallReturnOffset(call.m_jmp);
548     }
549 
repatchJump(CodeLocationJump jump,CodeLocationLabel destination)550     static void repatchJump(CodeLocationJump jump, CodeLocationLabel destination)
551     {
552         AssemblerType::relinkJump(jump.dataLocation(), destination.dataLocation());
553     }
554 
repatchNearCall(CodeLocationNearCall nearCall,CodeLocationLabel destination)555     static void repatchNearCall(CodeLocationNearCall nearCall, CodeLocationLabel destination)
556     {
557         AssemblerType::relinkCall(nearCall.dataLocation(), destination.executableAddress());
558     }
559 
repatchInt32(CodeLocationDataLabel32 dataLabel32,int32_t value)560     static void repatchInt32(CodeLocationDataLabel32 dataLabel32, int32_t value)
561     {
562         AssemblerType::repatchInt32(dataLabel32.dataLocation(), value);
563     }
564 
repatchPointer(CodeLocationDataLabelPtr dataLabelPtr,void * value)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