2 * Copyright (C) 2008, 2012 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 "AssemblerBuffer.h"
30 #include "CodeLocation.h"
31 #include "MacroAssemblerCodeRef.h"
32 #include <wtf/CryptographicallyRandomNumber.h>
33 #include <wtf/Noncopyable.h>
39 #define ENABLE_JIT_CONSTANT_BLINDING 0
42 #ifndef ENABLE_JIT_CONSTANT_BLINDING
43 #define ENABLE_JIT_CONSTANT_BLINDING 1
48 inline bool isARMv7s()
68 #if CPU(X86_64) || CPU(X86)
75 class JumpReplacementWatchpoint
;
83 template <class AssemblerType
>
84 class AbstractMacroAssembler
{
86 friend class JITWriteBarrierBase
;
87 typedef AssemblerType AssemblerType_T
;
89 typedef MacroAssemblerCodePtr CodePtr
;
90 typedef MacroAssemblerCodeRef CodeRef
;
94 typedef typename
AssemblerType::RegisterID RegisterID
;
96 // Section 1: MacroAssembler operand types
98 // The following types are used as operands to MacroAssembler operations,
99 // describing immediate and memory operands to the instructions to be planted.
110 // Describes a simple base-offset address.
112 explicit Address(RegisterID base
, int32_t offset
= 0)
122 struct ExtendedAddress
{
123 explicit ExtendedAddress(RegisterID base
, intptr_t offset
= 0)
135 // This class is used for explicit 'load' and 'store' operations
136 // (as opposed to situations in which a memory operand is provided
137 // to a generic operation, such as an integer arithmetic instruction).
139 // In the case of a load (or store) operation we want to permit
140 // addresses to be implicitly constructed, e.g. the two calls:
142 // load32(Address(addrReg), destReg);
143 // load32(addrReg, destReg);
145 // Are equivalent, and the explicit wrapping of the Address in the former
147 struct ImplicitAddress
{
148 ImplicitAddress(RegisterID base
)
154 ImplicitAddress(Address address
)
156 , offset(address
.offset
)
166 // Describes a complex addressing mode.
168 BaseIndex(RegisterID base
, RegisterID index
, Scale scale
, int32_t offset
= 0)
184 // Describes an memory operand given by a pointer. For regular load & store
185 // operations an unwrapped void* will be used, rather than using this.
186 struct AbsoluteAddress
{
187 explicit AbsoluteAddress(const void* ptr
)
197 // A pointer sized immediate operand to an instruction - this is wrapped
198 // in a class requiring explicit construction in order to differentiate
199 // from pointers used as absolute addresses to memory operations
200 struct TrustedImmPtr
{
203 explicit TrustedImmPtr(const void* value
)
208 // This is only here so that TrustedImmPtr(0) does not confuse the C++
209 // overload handling rules.
210 explicit TrustedImmPtr(int value
)
213 ASSERT_UNUSED(value
, !value
);
216 explicit TrustedImmPtr(size_t value
)
217 : m_value(reinterpret_cast<void*>(value
))
223 return reinterpret_cast<intptr_t>(m_value
);
230 #if ENABLE(JIT_CONSTANT_BLINDING)
231 private TrustedImmPtr
236 explicit ImmPtr(const void* value
)
237 : TrustedImmPtr(value
)
241 TrustedImmPtr
asTrustedImmPtr() { return *this; }
246 // A 32bit immediate operand to an instruction - this is wrapped in a
247 // class requiring explicit construction in order to prevent RegisterIDs
248 // (which are implemented as an enum) from accidentally being passed as
250 struct TrustedImm32
{
253 explicit TrustedImm32(int32_t value
)
259 explicit TrustedImm32(TrustedImmPtr ptr
)
260 : m_value(ptr
.asIntptr())
270 #if ENABLE(JIT_CONSTANT_BLINDING)
276 explicit Imm32(int32_t value
)
277 : TrustedImm32(value
)
281 explicit Imm32(TrustedImmPtr ptr
)
286 const TrustedImm32
& asTrustedImm32() const { return *this; }
292 // A 64bit immediate operand to an instruction - this is wrapped in a
293 // class requiring explicit construction in order to prevent RegisterIDs
294 // (which are implemented as an enum) from accidentally being passed as
296 struct TrustedImm64
{
299 explicit TrustedImm64(int64_t value
)
304 #if CPU(X86_64) || CPU(ARM64)
305 explicit TrustedImm64(TrustedImmPtr ptr
)
306 : m_value(ptr
.asIntptr())
315 #if ENABLE(JIT_CONSTANT_BLINDING)
321 explicit Imm64(int64_t value
)
322 : TrustedImm64(value
)
325 #if CPU(X86_64) || CPU(ARM64)
326 explicit Imm64(TrustedImmPtr ptr
)
331 const TrustedImm64
& asTrustedImm64() const { return *this; }
334 // Section 2: MacroAssembler code buffer handles
336 // The following types are used to reference items in the code buffer
337 // during JIT code generation. For example, the type Jump is used to
338 // track the location of a jump instruction so that it may later be
339 // linked to a label marking its destination.
344 // A Label records a point in the generated instruction stream, typically such that
345 // it may be used as a destination for a jump.
347 template<class TemplateAssemblerType
>
348 friend class AbstractMacroAssembler
;
349 friend struct DFG::OSRExit
;
351 friend class JumpReplacementWatchpoint
;
352 friend class MacroAssemblerCodeRef
;
353 friend class LinkBuffer
;
354 friend class Watchpoint
;
361 Label(AbstractMacroAssembler
<AssemblerType
>* masm
)
362 : m_label(masm
->m_assembler
.label())
364 masm
->invalidateAllTempRegisters();
367 bool isSet() const { return m_label
.isSet(); }
369 AssemblerLabel m_label
;
372 // ConvertibleLoadLabel:
374 // A ConvertibleLoadLabel records a loadPtr instruction that can be patched to an addPtr
377 // loadPtr(Address(a, i), b)
381 // addPtr(TrustedImmPtr(i), a, b)
382 class ConvertibleLoadLabel
{
383 template<class TemplateAssemblerType
>
384 friend class AbstractMacroAssembler
;
385 friend class LinkBuffer
;
388 ConvertibleLoadLabel()
392 ConvertibleLoadLabel(AbstractMacroAssembler
<AssemblerType
>* masm
)
393 : m_label(masm
->m_assembler
.labelIgnoringWatchpoints())
397 bool isSet() const { return m_label
.isSet(); }
399 AssemblerLabel m_label
;
404 // A DataLabelPtr is used to refer to a location in the code containing a pointer to be
405 // patched after the code has been generated.
407 template<class TemplateAssemblerType
>
408 friend class AbstractMacroAssembler
;
409 friend class LinkBuffer
;
415 DataLabelPtr(AbstractMacroAssembler
<AssemblerType
>* masm
)
416 : m_label(masm
->m_assembler
.label())
420 bool isSet() const { return m_label
.isSet(); }
423 AssemblerLabel m_label
;
428 // A DataLabelPtr is used to refer to a location in the code containing a pointer to be
429 // patched after the code has been generated.
431 template<class TemplateAssemblerType
>
432 friend class AbstractMacroAssembler
;
433 friend class LinkBuffer
;
439 DataLabel32(AbstractMacroAssembler
<AssemblerType
>* masm
)
440 : m_label(masm
->m_assembler
.label())
444 AssemblerLabel
label() const { return m_label
; }
447 AssemblerLabel m_label
;
452 // A DataLabelCompact is used to refer to a location in the code containing a
453 // compact immediate to be patched after the code has been generated.
454 class DataLabelCompact
{
455 template<class TemplateAssemblerType
>
456 friend class AbstractMacroAssembler
;
457 friend class LinkBuffer
;
463 DataLabelCompact(AbstractMacroAssembler
<AssemblerType
>* masm
)
464 : m_label(masm
->m_assembler
.label())
468 DataLabelCompact(AssemblerLabel label
)
474 AssemblerLabel m_label
;
479 // A Call object is a reference to a call instruction that has been planted
480 // into the code buffer - it is typically used to link the call, setting the
481 // relative offset such that when executed it will call to the desired
484 template<class TemplateAssemblerType
>
485 friend class AbstractMacroAssembler
;
500 Call(AssemblerLabel jmp
, Flags flags
)
506 bool isFlagSet(Flags flag
)
508 return m_flags
& flag
;
511 static Call
fromTailJump(Jump jump
)
513 return Call(jump
.m_label
, Linkable
);
516 AssemblerLabel m_label
;
523 // A jump object is a reference to a jump instruction that has been planted
524 // into the code buffer - it is typically used to link the jump, setting the
525 // relative offset such that when executed it will jump to the desired
528 template<class TemplateAssemblerType
>
529 friend class AbstractMacroAssembler
;
531 friend struct DFG::OSRExit
;
532 friend class LinkBuffer
;
539 // Fixme: this information should be stored in the instruction stream, not in the Jump object.
540 Jump(AssemblerLabel jmp
, ARMv7Assembler::JumpType type
= ARMv7Assembler::JumpNoCondition
, ARMv7Assembler::Condition condition
= ARMv7Assembler::ConditionInvalid
)
543 , m_condition(condition
)
547 Jump(AssemblerLabel jmp
, ARM64Assembler::JumpType type
= ARM64Assembler::JumpNoCondition
, ARM64Assembler::Condition condition
= ARM64Assembler::ConditionInvalid
)
550 , m_condition(condition
)
554 Jump(AssemblerLabel jmp
, ARM64Assembler::JumpType type
, ARM64Assembler::Condition condition
, bool is64Bit
, ARM64Assembler::RegisterID compareRegister
)
557 , m_condition(condition
)
559 , m_compareRegister(compareRegister
)
561 ASSERT((type
== ARM64Assembler::JumpCompareAndBranch
) || (type
== ARM64Assembler::JumpCompareAndBranchFixedSize
));
564 Jump(AssemblerLabel jmp
, ARM64Assembler::JumpType type
, ARM64Assembler::Condition condition
, unsigned bitNumber
, ARM64Assembler::RegisterID compareRegister
)
567 , m_condition(condition
)
568 , m_bitNumber(bitNumber
)
569 , m_compareRegister(compareRegister
)
571 ASSERT((type
== ARM64Assembler::JumpTestBit
) || (type
== ARM64Assembler::JumpTestBitFixedSize
));
574 Jump(AssemblerLabel jmp
, SH4Assembler::JumpType type
= SH4Assembler::JumpFar
)
580 Jump(AssemblerLabel jmp
)
589 result
.m_label
= m_label
;
593 void link(AbstractMacroAssembler
<AssemblerType
>* masm
) const
595 masm
->invalidateAllTempRegisters();
597 #if ENABLE(DFG_REGISTER_ALLOCATION_VALIDATION)
598 masm
->checkRegisterAllocationAgainstBranchRange(m_label
.m_offset
, masm
->debugOffset());
602 masm
->m_assembler
.linkJump(m_label
, masm
->m_assembler
.label(), m_type
, m_condition
);
604 if ((m_type
== ARM64Assembler::JumpCompareAndBranch
) || (m_type
== ARM64Assembler::JumpCompareAndBranchFixedSize
))
605 masm
->m_assembler
.linkJump(m_label
, masm
->m_assembler
.label(), m_type
, m_condition
, m_is64Bit
, m_compareRegister
);
606 else if ((m_type
== ARM64Assembler::JumpTestBit
) || (m_type
== ARM64Assembler::JumpTestBitFixedSize
))
607 masm
->m_assembler
.linkJump(m_label
, masm
->m_assembler
.label(), m_type
, m_condition
, m_bitNumber
, m_compareRegister
);
609 masm
->m_assembler
.linkJump(m_label
, masm
->m_assembler
.label(), m_type
, m_condition
);
611 masm
->m_assembler
.linkJump(m_label
, masm
->m_assembler
.label(), m_type
);
613 masm
->m_assembler
.linkJump(m_label
, masm
->m_assembler
.label());
617 void linkTo(Label label
, AbstractMacroAssembler
<AssemblerType
>* masm
) const
619 #if ENABLE(DFG_REGISTER_ALLOCATION_VALIDATION)
620 masm
->checkRegisterAllocationAgainstBranchRange(label
.m_label
.m_offset
, m_label
.m_offset
);
624 masm
->m_assembler
.linkJump(m_label
, label
.m_label
, m_type
, m_condition
);
626 if ((m_type
== ARM64Assembler::JumpCompareAndBranch
) || (m_type
== ARM64Assembler::JumpCompareAndBranchFixedSize
))
627 masm
->m_assembler
.linkJump(m_label
, label
.m_label
, m_type
, m_condition
, m_is64Bit
, m_compareRegister
);
628 else if ((m_type
== ARM64Assembler::JumpTestBit
) || (m_type
== ARM64Assembler::JumpTestBitFixedSize
))
629 masm
->m_assembler
.linkJump(m_label
, label
.m_label
, m_type
, m_condition
, m_bitNumber
, m_compareRegister
);
631 masm
->m_assembler
.linkJump(m_label
, label
.m_label
, m_type
, m_condition
);
633 masm
->m_assembler
.linkJump(m_label
, label
.m_label
);
637 bool isSet() const { return m_label
.isSet(); }
640 AssemblerLabel m_label
;
642 ARMv7Assembler::JumpType m_type
;
643 ARMv7Assembler::Condition m_condition
;
645 ARM64Assembler::JumpType m_type
;
646 ARM64Assembler::Condition m_condition
;
648 unsigned m_bitNumber
;
649 ARM64Assembler::RegisterID m_compareRegister
;
652 SH4Assembler::JumpType m_type
;
656 struct PatchableJump
{
661 explicit PatchableJump(Jump jump
)
666 operator Jump
&() { return m_jump
; }
673 // A JumpList is a set of Jump objects.
674 // All jumps in the set will be linked to the same destination.
676 friend class LinkBuffer
;
679 typedef Vector
<Jump
, 2> JumpVector
;
688 void link(AbstractMacroAssembler
<AssemblerType
>* masm
)
690 size_t size
= m_jumps
.size();
691 for (size_t i
= 0; i
< size
; ++i
)
692 m_jumps
[i
].link(masm
);
696 void linkTo(Label label
, AbstractMacroAssembler
<AssemblerType
>* masm
)
698 size_t size
= m_jumps
.size();
699 for (size_t i
= 0; i
< size
; ++i
)
700 m_jumps
[i
].linkTo(label
, masm
);
704 void append(Jump jump
)
706 m_jumps
.append(jump
);
709 void append(const JumpList
& other
)
711 m_jumps
.append(other
.m_jumps
.begin(), other
.m_jumps
.size());
716 return !m_jumps
.size();
724 const JumpVector
& jumps() const { return m_jumps
; }
731 // Section 3: Misc admin methods
733 Label
labelIgnoringWatchpoints()
736 result
.m_label
= m_assembler
.labelIgnoringWatchpoints();
740 Label
labelIgnoringWatchpoints()
751 void padBeforePatch()
753 // Rely on the fact that asking for a label already does the padding.
757 Label
watchpointLabel()
760 result
.m_label
= m_assembler
.labelForWatchpoint();
766 m_assembler
.align(16);
770 #if ENABLE(DFG_REGISTER_ALLOCATION_VALIDATION)
771 class RegisterAllocationOffset
{
773 RegisterAllocationOffset(unsigned offset
)
778 void check(unsigned low
, unsigned high
)
780 RELEASE_ASSERT_WITH_MESSAGE(!(low
<= m_offset
&& m_offset
<= high
), "Unsafe branch over register allocation at instruction offset %u in jump offset range %u..%u", m_offset
, low
, high
);
787 void addRegisterAllocationAtOffset(unsigned offset
)
789 m_registerAllocationForOffsets
.append(RegisterAllocationOffset(offset
));
792 void clearRegisterAllocationOffsets()
794 m_registerAllocationForOffsets
.clear();
797 void checkRegisterAllocationAgainstBranchRange(unsigned offset1
, unsigned offset2
)
799 if (offset1
> offset2
)
800 std::swap(offset1
, offset2
);
802 size_t size
= m_registerAllocationForOffsets
.size();
803 for (size_t i
= 0; i
< size
; ++i
)
804 m_registerAllocationForOffsets
[i
].check(offset1
, offset2
);
808 template<typename T
, typename U
>
809 static ptrdiff_t differenceBetween(T from
, U to
)
811 return AssemblerType::getDifferenceBetweenLabels(from
.m_label
, to
.m_label
);
814 static ptrdiff_t differenceBetweenCodePtr(const MacroAssemblerCodePtr
& a
, const MacroAssemblerCodePtr
& b
)
816 return reinterpret_cast<ptrdiff_t>(b
.executableAddress()) - reinterpret_cast<ptrdiff_t>(a
.executableAddress());
819 unsigned debugOffset() { return m_assembler
.debugOffset(); }
821 ALWAYS_INLINE
static void cacheFlush(void* code
, size_t size
)
823 AssemblerType::cacheFlush(code
, size
);
826 AbstractMacroAssembler()
827 : m_randomSource(cryptographicallyRandomNumber())
831 AssemblerType m_assembler
;
835 return m_randomSource
.getUint32();
838 WeakRandom m_randomSource
;
840 #if ENABLE(DFG_REGISTER_ALLOCATION_VALIDATION)
841 Vector
<RegisterAllocationOffset
, 10> m_registerAllocationForOffsets
;
844 #if ENABLE(JIT_CONSTANT_BLINDING)
845 static bool scratchRegisterForBlinding() { return false; }
846 static bool shouldBlindForSpecificArch(uint32_t) { return true; }
847 static bool shouldBlindForSpecificArch(uint64_t) { return true; }
850 class CachedTempRegister
{
851 friend class DataLabelPtr
;
852 friend class DataLabel32
;
853 friend class DataLabelCompact
;
858 CachedTempRegister(AbstractMacroAssembler
<AssemblerType
>* masm
, RegisterID registerID
)
860 , m_registerID(registerID
)
862 , m_validBit(1 << static_cast<unsigned>(registerID
))
864 ASSERT(static_cast<unsigned>(registerID
) < (sizeof(unsigned) * 8));
867 ALWAYS_INLINE RegisterID
registerIDInvalidate() { invalidate(); return m_registerID
; }
869 ALWAYS_INLINE RegisterID
registerIDNoInvalidate() { return m_registerID
; }
871 bool value(intptr_t& value
)
874 return m_masm
->isTempRegisterValid(m_validBit
);
877 void setValue(intptr_t value
)
880 m_masm
->setTempRegisterValid(m_validBit
);
883 ALWAYS_INLINE
void invalidate() { m_masm
->clearTempRegisterValid(m_validBit
); }
886 AbstractMacroAssembler
<AssemblerType
>* m_masm
;
887 RegisterID m_registerID
;
892 ALWAYS_INLINE
void invalidateAllTempRegisters()
894 m_tempRegistersValidBits
= 0;
897 ALWAYS_INLINE
bool isTempRegisterValid(unsigned registerMask
)
899 return (m_tempRegistersValidBits
& registerMask
);
902 ALWAYS_INLINE
void clearTempRegisterValid(unsigned registerMask
)
904 m_tempRegistersValidBits
&= ~registerMask
;
907 ALWAYS_INLINE
void setTempRegisterValid(unsigned registerMask
)
909 m_tempRegistersValidBits
|= registerMask
;
912 unsigned m_tempRegistersValidBits
;
914 friend class LinkBuffer
;
915 friend class RepatchBuffer
;
917 static void linkJump(void* code
, Jump jump
, CodeLocationLabel target
)
919 AssemblerType::linkJump(code
, jump
.m_label
, target
.dataLocation());
922 static void linkPointer(void* code
, AssemblerLabel label
, void* value
)
924 AssemblerType::linkPointer(code
, label
, value
);
927 static void* getLinkerAddress(void* code
, AssemblerLabel label
)
929 return AssemblerType::getRelocatedAddress(code
, label
);
932 static unsigned getLinkerCallReturnOffset(Call call
)
934 return AssemblerType::getCallReturnOffset(call
.m_label
);
937 static void repatchJump(CodeLocationJump jump
, CodeLocationLabel destination
)
939 AssemblerType::relinkJump(jump
.dataLocation(), destination
.dataLocation());
942 static void repatchNearCall(CodeLocationNearCall nearCall
, CodeLocationLabel destination
)
944 AssemblerType::relinkCall(nearCall
.dataLocation(), destination
.executableAddress());
947 static void repatchCompact(CodeLocationDataLabelCompact dataLabelCompact
, int32_t value
)
949 AssemblerType::repatchCompact(dataLabelCompact
.dataLocation(), value
);
952 static void repatchInt32(CodeLocationDataLabel32 dataLabel32
, int32_t value
)
954 AssemblerType::repatchInt32(dataLabel32
.dataLocation(), value
);
957 static void repatchPointer(CodeLocationDataLabelPtr dataLabelPtr
, void* value
)
959 AssemblerType::repatchPointer(dataLabelPtr
.dataLocation(), value
);
962 static void* readPointer(CodeLocationDataLabelPtr dataLabelPtr
)
964 return AssemblerType::readPointer(dataLabelPtr
.dataLocation());
967 static void replaceWithLoad(CodeLocationConvertibleLoad label
)
969 AssemblerType::replaceWithLoad(label
.dataLocation());
972 static void replaceWithAddressComputation(CodeLocationConvertibleLoad label
)
974 AssemblerType::replaceWithAddressComputation(label
.dataLocation());
980 #endif // ENABLE(ASSEMBLER)
982 #endif // AbstractMacroAssembler_h