• 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