2 * Copyright (C) 2008 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
26 #ifndef AbstractMacroAssembler_h
27 #define AbstractMacroAssembler_h
29 #include "CodeLocation.h"
30 #include "MacroAssemblerCodeRef.h"
31 #include <wtf/Noncopyable.h>
32 #include <wtf/UnusedParam.h>
41 template <class AssemblerType
>
42 class AbstractMacroAssembler
{
44 friend class JITWriteBarrierBase
;
45 typedef AssemblerType AssemblerType_T
;
47 typedef MacroAssemblerCodePtr CodePtr
;
48 typedef MacroAssemblerCodeRef CodeRef
;
52 typedef typename
AssemblerType::RegisterID RegisterID
;
54 // Section 1: MacroAssembler operand types
56 // The following types are used as operands to MacroAssembler operations,
57 // describing immediate and memory operands to the instructions to be planted.
69 // Describes a simple base-offset address.
71 explicit Address(RegisterID base
, int32_t offset
= 0)
81 struct ExtendedAddress
{
82 explicit ExtendedAddress(RegisterID base
, intptr_t offset
= 0)
94 // This class is used for explicit 'load' and 'store' operations
95 // (as opposed to situations in which a memory operand is provided
96 // to a generic operation, such as an integer arithmetic instruction).
98 // In the case of a load (or store) operation we want to permit
99 // addresses to be implicitly constructed, e.g. the two calls:
101 // load32(Address(addrReg), destReg);
102 // load32(addrReg, destReg);
104 // Are equivalent, and the explicit wrapping of the Address in the former
106 struct ImplicitAddress
{
107 ImplicitAddress(RegisterID base
)
113 ImplicitAddress(Address address
)
115 , offset(address
.offset
)
125 // Describes a complex addressing mode.
127 BaseIndex(RegisterID base
, RegisterID index
, Scale scale
, int32_t offset
= 0)
143 // Describes an memory operand given by a pointer. For regular load & store
144 // operations an unwrapped void* will be used, rather than using this.
145 struct AbsoluteAddress
{
146 explicit AbsoluteAddress(const void* ptr
)
156 // A pointer sized immediate operand to an instruction - this is wrapped
157 // in a class requiring explicit construction in order to differentiate
158 // from pointers used as absolute addresses to memory operations
159 struct TrustedImmPtr
{
160 explicit TrustedImmPtr(const void* value
)
167 return reinterpret_cast<intptr_t>(m_value
);
173 struct ImmPtr
: public TrustedImmPtr
{
174 explicit ImmPtr(const void* value
)
175 : TrustedImmPtr(value
)
182 // A 32bit immediate operand to an instruction - this is wrapped in a
183 // class requiring explicit construction in order to prevent RegisterIDs
184 // (which are implemented as an enum) from accidentally being passed as
186 struct TrustedImm32
{
187 explicit TrustedImm32(int32_t value
)
189 #if CPU(ARM) || CPU(MIPS)
196 explicit TrustedImm32(TrustedImmPtr ptr
)
197 : m_value(ptr
.asIntptr())
198 #if CPU(ARM) || CPU(MIPS)
206 #if CPU(ARM) || CPU(MIPS)
207 // We rely on being able to regenerate code to recover exception handling
208 // information. Since ARMv7 supports 16-bit immediates there is a danger
209 // that if pointer values change the layout of the generated code will change.
210 // To avoid this problem, always generate pointers (and thus Imm32s constructed
211 // from ImmPtrs) with a code sequence that is able to represent any pointer
212 // value - don't use a more compact form in these cases.
219 struct Imm32
: public TrustedImm32
{
220 explicit Imm32(int32_t value
)
221 : TrustedImm32(value
)
225 explicit Imm32(TrustedImmPtr ptr
)
232 // Section 2: MacroAssembler code buffer handles
234 // The following types are used to reference items in the code buffer
235 // during JIT code generation. For example, the type Jump is used to
236 // track the location of a jump instruction so that it may later be
237 // linked to a label marking its destination.
242 // A Label records a point in the generated instruction stream, typically such that
243 // it may be used as a destination for a jump.
245 template<class TemplateAssemblerType
>
246 friend class AbstractMacroAssembler
;
248 friend class MacroAssemblerCodeRef
;
249 friend class LinkBuffer
;
256 Label(AbstractMacroAssembler
<AssemblerType
>* masm
)
257 : m_label(masm
->m_assembler
.label())
261 bool isSet() const { return m_label
.isSet(); }
263 AssemblerLabel m_label
;
268 // A DataLabelPtr is used to refer to a location in the code containing a pointer to be
269 // patched after the code has been generated.
271 template<class TemplateAssemblerType
>
272 friend class AbstractMacroAssembler
;
273 friend class LinkBuffer
;
279 DataLabelPtr(AbstractMacroAssembler
<AssemblerType
>* masm
)
280 : m_label(masm
->m_assembler
.label())
284 bool isSet() const { return m_label
.isSet(); }
287 AssemblerLabel m_label
;
292 // A DataLabelPtr is used to refer to a location in the code containing a pointer to be
293 // patched after the code has been generated.
295 template<class TemplateAssemblerType
>
296 friend class AbstractMacroAssembler
;
297 friend class LinkBuffer
;
303 DataLabel32(AbstractMacroAssembler
<AssemblerType
>* masm
)
304 : m_label(masm
->m_assembler
.label())
308 AssemblerLabel
label() const { return m_label
; }
311 AssemblerLabel m_label
;
316 // A DataLabelCompact is used to refer to a location in the code containing a
317 // compact immediate to be patched after the code has been generated.
318 class DataLabelCompact
{
319 template<class TemplateAssemblerType
>
320 friend class AbstractMacroAssembler
;
321 friend class LinkBuffer
;
327 DataLabelCompact(AbstractMacroAssembler
<AssemblerType
>* masm
)
328 : m_label(masm
->m_assembler
.label())
332 DataLabelCompact(AssemblerLabel label
)
338 AssemblerLabel m_label
;
343 // A Call object is a reference to a call instruction that has been planted
344 // into the code buffer - it is typically used to link the call, setting the
345 // relative offset such that when executed it will call to the desired
348 template<class TemplateAssemblerType
>
349 friend class AbstractMacroAssembler
;
364 Call(AssemblerLabel jmp
, Flags flags
)
370 bool isFlagSet(Flags flag
)
372 return m_flags
& flag
;
375 static Call
fromTailJump(Jump jump
)
377 return Call(jump
.m_jmp
, Linkable
);
380 AssemblerLabel m_jmp
;
387 // A jump object is a reference to a jump instruction that has been planted
388 // into the code buffer - it is typically used to link the jump, setting the
389 // relative offset such that when executed it will jump to the desired
392 template<class TemplateAssemblerType
>
393 friend class AbstractMacroAssembler
;
395 friend class LinkBuffer
;
402 // Fixme: this information should be stored in the instruction stream, not in the Jump object.
403 Jump(AssemblerLabel jmp
, ARMv7Assembler::JumpType type
, ARMv7Assembler::Condition condition
= ARMv7Assembler::ConditionInvalid
)
406 , m_condition(condition
)
410 Jump(AssemblerLabel jmp
)
416 void link(AbstractMacroAssembler
<AssemblerType
>* masm
) const
419 masm
->m_assembler
.linkJump(m_jmp
, masm
->m_assembler
.label(), m_type
, m_condition
);
421 masm
->m_assembler
.linkJump(m_jmp
, masm
->m_assembler
.label());
425 void linkTo(Label label
, AbstractMacroAssembler
<AssemblerType
>* masm
) const
428 masm
->m_assembler
.linkJump(m_jmp
, label
.m_label
, m_type
, m_condition
);
430 masm
->m_assembler
.linkJump(m_jmp
, label
.m_label
);
434 bool isSet() const { return m_jmp
.isSet(); }
437 AssemblerLabel m_jmp
;
439 ARMv7Assembler::JumpType m_type
;
440 ARMv7Assembler::Condition m_condition
;
446 // A JumpList is a set of Jump objects.
447 // All jumps in the set will be linked to the same destination.
449 friend class LinkBuffer
;
452 typedef Vector
<Jump
, 16> JumpVector
;
454 void link(AbstractMacroAssembler
<AssemblerType
>* masm
)
456 size_t size
= m_jumps
.size();
457 for (size_t i
= 0; i
< size
; ++i
)
458 m_jumps
[i
].link(masm
);
462 void linkTo(Label label
, AbstractMacroAssembler
<AssemblerType
>* masm
)
464 size_t size
= m_jumps
.size();
465 for (size_t i
= 0; i
< size
; ++i
)
466 m_jumps
[i
].linkTo(label
, masm
);
470 void append(Jump jump
)
472 m_jumps
.append(jump
);
475 void append(JumpList
& other
)
477 m_jumps
.append(other
.m_jumps
.begin(), other
.m_jumps
.size());
482 return !m_jumps
.size();
490 const JumpVector
& jumps() { return m_jumps
; }
497 // Section 3: Misc admin methods
505 m_assembler
.align(16);
509 ptrdiff_t differenceBetween(Label from
, Jump to
)
511 return AssemblerType::getDifferenceBetweenLabels(from
.m_label
, to
.m_jmp
);
514 ptrdiff_t differenceBetween(Label from
, Call to
)
516 return AssemblerType::getDifferenceBetweenLabels(from
.m_label
, to
.m_jmp
);
519 ptrdiff_t differenceBetween(Label from
, Label to
)
521 return AssemblerType::getDifferenceBetweenLabels(from
.m_label
, to
.m_label
);
524 ptrdiff_t differenceBetween(Label from
, DataLabelPtr to
)
526 return AssemblerType::getDifferenceBetweenLabels(from
.m_label
, to
.m_label
);
529 ptrdiff_t differenceBetween(Label from
, DataLabel32 to
)
531 return AssemblerType::getDifferenceBetweenLabels(from
.m_label
, to
.m_label
);
534 ptrdiff_t differenceBetween(Label from
, DataLabelCompact to
)
536 return AssemblerType::getDifferenceBetweenLabels(from
.m_label
, to
.m_label
);
539 ptrdiff_t differenceBetween(DataLabelPtr from
, Jump to
)
541 return AssemblerType::getDifferenceBetweenLabels(from
.m_label
, to
.m_jmp
);
544 ptrdiff_t differenceBetween(DataLabelPtr from
, DataLabelPtr to
)
546 return AssemblerType::getDifferenceBetweenLabels(from
.m_label
, to
.m_label
);
549 ptrdiff_t differenceBetween(DataLabelPtr from
, Call to
)
551 return AssemblerType::getDifferenceBetweenLabels(from
.m_label
, to
.m_jmp
);
554 // Temporary interface; likely to be removed, since may be hard to port to all architectures.
555 #if CPU(X86) || CPU(X86_64)
556 void rewindToLabel(Label rewindTo
) { m_assembler
.rewindToLabel(rewindTo
.m_label
); }
559 void beginUninterruptedSequence() { }
560 void endUninterruptedSequence() { }
563 unsigned debugOffset() { return m_assembler
.debugOffset(); }
567 AssemblerType m_assembler
;
569 friend class LinkBuffer
;
570 friend class RepatchBuffer
;
572 static void linkJump(void* code
, Jump jump
, CodeLocationLabel target
)
574 AssemblerType::linkJump(code
, jump
.m_jmp
, target
.dataLocation());
577 static void linkPointer(void* code
, AssemblerLabel label
, void* value
)
579 AssemblerType::linkPointer(code
, label
, value
);
582 static void* getLinkerAddress(void* code
, AssemblerLabel label
)
584 return AssemblerType::getRelocatedAddress(code
, label
);
587 static unsigned getLinkerCallReturnOffset(Call call
)
589 return AssemblerType::getCallReturnOffset(call
.m_jmp
);
592 static void repatchJump(CodeLocationJump jump
, CodeLocationLabel destination
)
594 AssemblerType::relinkJump(jump
.dataLocation(), destination
.dataLocation());
597 static void repatchNearCall(CodeLocationNearCall nearCall
, CodeLocationLabel destination
)
599 AssemblerType::relinkCall(nearCall
.dataLocation(), destination
.executableAddress());
602 static void repatchCompact(CodeLocationDataLabelCompact dataLabelCompact
, int32_t value
)
604 AssemblerType::repatchCompact(dataLabelCompact
.dataLocation(), value
);
607 static void repatchInt32(CodeLocationDataLabel32 dataLabel32
, int32_t value
)
609 AssemblerType::repatchInt32(dataLabel32
.dataLocation(), value
);
612 static void repatchPointer(CodeLocationDataLabelPtr dataLabelPtr
, void* value
)
614 AssemblerType::repatchPointer(dataLabelPtr
.dataLocation(), value
);
617 static void* readPointer(CodeLocationDataLabelPtr dataLabelPtr
)
619 return AssemblerType::readPointer(dataLabelPtr
.dataLocation());
625 #endif // ENABLE(ASSEMBLER)
627 #endif // AbstractMacroAssembler_h