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 "AssemblerBuffer.h"
30 #include "CodeLocation.h"
31 #include "MacroAssemblerCodeRef.h"
32 #include <wtf/CryptographicallyRandomNumber.h>
33 #include <wtf/Noncopyable.h>
34 #include <wtf/UnusedParam.h>
40 #define ENABLE_JIT_CONSTANT_BLINDING 0
43 #ifndef ENABLE_JIT_CONSTANT_BLINDING
44 #define ENABLE_JIT_CONSTANT_BLINDING 1
52 class CorrectableJumpPoint
;
55 template <class AssemblerType
>
56 class AbstractMacroAssembler
{
58 friend class JITWriteBarrierBase
;
59 typedef AssemblerType AssemblerType_T
;
61 typedef MacroAssemblerCodePtr CodePtr
;
62 typedef MacroAssemblerCodeRef CodeRef
;
66 typedef typename
AssemblerType::RegisterID RegisterID
;
68 // Section 1: MacroAssembler operand types
70 // The following types are used as operands to MacroAssembler operations,
71 // describing immediate and memory operands to the instructions to be planted.
83 // Describes a simple base-offset address.
85 explicit Address(RegisterID base
, int32_t offset
= 0)
95 struct ExtendedAddress
{
96 explicit ExtendedAddress(RegisterID base
, intptr_t offset
= 0)
108 // This class is used for explicit 'load' and 'store' operations
109 // (as opposed to situations in which a memory operand is provided
110 // to a generic operation, such as an integer arithmetic instruction).
112 // In the case of a load (or store) operation we want to permit
113 // addresses to be implicitly constructed, e.g. the two calls:
115 // load32(Address(addrReg), destReg);
116 // load32(addrReg, destReg);
118 // Are equivalent, and the explicit wrapping of the Address in the former
120 struct ImplicitAddress
{
121 ImplicitAddress(RegisterID base
)
127 ImplicitAddress(Address address
)
129 , offset(address
.offset
)
139 // Describes a complex addressing mode.
141 BaseIndex(RegisterID base
, RegisterID index
, Scale scale
, int32_t offset
= 0)
157 // Describes an memory operand given by a pointer. For regular load & store
158 // operations an unwrapped void* will be used, rather than using this.
159 struct AbsoluteAddress
{
160 explicit AbsoluteAddress(const void* ptr
)
170 // A pointer sized immediate operand to an instruction - this is wrapped
171 // in a class requiring explicit construction in order to differentiate
172 // from pointers used as absolute addresses to memory operations
173 struct TrustedImmPtr
{
174 explicit TrustedImmPtr(const void* value
)
179 // This is only here so that TrustedImmPtr(0) does not confuse the C++
180 // overload handling rules.
181 explicit TrustedImmPtr(int value
)
184 ASSERT_UNUSED(value
, !value
);
187 explicit TrustedImmPtr(size_t value
)
188 : m_value(reinterpret_cast<void*>(value
))
194 return reinterpret_cast<intptr_t>(m_value
);
201 #if ENABLE(JIT_CONSTANT_BLINDING)
202 private TrustedImmPtr
207 explicit ImmPtr(const void* value
)
208 : TrustedImmPtr(value
)
212 TrustedImmPtr
asTrustedImmPtr() { return *this; }
217 // A 32bit immediate operand to an instruction - this is wrapped in a
218 // class requiring explicit construction in order to prevent RegisterIDs
219 // (which are implemented as an enum) from accidentally being passed as
221 struct TrustedImm32
{
222 explicit TrustedImm32(int32_t value
)
224 #if CPU(ARM) || CPU(MIPS)
231 explicit TrustedImm32(TrustedImmPtr ptr
)
232 : m_value(ptr
.asIntptr())
233 #if CPU(ARM) || CPU(MIPS)
241 #if CPU(ARM) || CPU(MIPS)
242 // We rely on being able to regenerate code to recover exception handling
243 // information. Since ARMv7 supports 16-bit immediates there is a danger
244 // that if pointer values change the layout of the generated code will change.
245 // To avoid this problem, always generate pointers (and thus Imm32s constructed
246 // from ImmPtrs) with a code sequence that is able to represent any pointer
247 // value - don't use a more compact form in these cases.
255 #if ENABLE(JIT_CONSTANT_BLINDING)
261 explicit Imm32(int32_t value
)
262 : TrustedImm32(value
)
266 explicit Imm32(TrustedImmPtr ptr
)
271 const TrustedImm32
& asTrustedImm32() const { return *this; }
275 // Section 2: MacroAssembler code buffer handles
277 // The following types are used to reference items in the code buffer
278 // during JIT code generation. For example, the type Jump is used to
279 // track the location of a jump instruction so that it may later be
280 // linked to a label marking its destination.
285 // A Label records a point in the generated instruction stream, typically such that
286 // it may be used as a destination for a jump.
288 template<class TemplateAssemblerType
>
289 friend class AbstractMacroAssembler
;
290 friend class DFG::CorrectableJumpPoint
;
292 friend class MacroAssemblerCodeRef
;
293 friend class LinkBuffer
;
300 Label(AbstractMacroAssembler
<AssemblerType
>* masm
)
301 : m_label(masm
->m_assembler
.label())
305 bool isSet() const { return m_label
.isSet(); }
307 AssemblerLabel m_label
;
312 // A DataLabelPtr is used to refer to a location in the code containing a pointer to be
313 // patched after the code has been generated.
315 template<class TemplateAssemblerType
>
316 friend class AbstractMacroAssembler
;
317 friend class LinkBuffer
;
323 DataLabelPtr(AbstractMacroAssembler
<AssemblerType
>* masm
)
324 : m_label(masm
->m_assembler
.label())
328 bool isSet() const { return m_label
.isSet(); }
331 AssemblerLabel m_label
;
336 // A DataLabelPtr is used to refer to a location in the code containing a pointer to be
337 // patched after the code has been generated.
339 template<class TemplateAssemblerType
>
340 friend class AbstractMacroAssembler
;
341 friend class LinkBuffer
;
347 DataLabel32(AbstractMacroAssembler
<AssemblerType
>* masm
)
348 : m_label(masm
->m_assembler
.label())
352 AssemblerLabel
label() const { return m_label
; }
355 AssemblerLabel m_label
;
360 // A DataLabelCompact is used to refer to a location in the code containing a
361 // compact immediate to be patched after the code has been generated.
362 class DataLabelCompact
{
363 template<class TemplateAssemblerType
>
364 friend class AbstractMacroAssembler
;
365 friend class LinkBuffer
;
371 DataLabelCompact(AbstractMacroAssembler
<AssemblerType
>* masm
)
372 : m_label(masm
->m_assembler
.label())
376 DataLabelCompact(AssemblerLabel label
)
382 AssemblerLabel m_label
;
387 // A Call object is a reference to a call instruction that has been planted
388 // into the code buffer - it is typically used to link the call, setting the
389 // relative offset such that when executed it will call to the desired
392 template<class TemplateAssemblerType
>
393 friend class AbstractMacroAssembler
;
408 Call(AssemblerLabel jmp
, Flags flags
)
414 bool isFlagSet(Flags flag
)
416 return m_flags
& flag
;
419 static Call
fromTailJump(Jump jump
)
421 return Call(jump
.m_label
, Linkable
);
424 AssemblerLabel m_label
;
431 // A jump object is a reference to a jump instruction that has been planted
432 // into the code buffer - it is typically used to link the jump, setting the
433 // relative offset such that when executed it will jump to the desired
436 template<class TemplateAssemblerType
>
437 friend class AbstractMacroAssembler
;
439 friend class DFG::CorrectableJumpPoint
;
440 friend class LinkBuffer
;
447 // Fixme: this information should be stored in the instruction stream, not in the Jump object.
448 Jump(AssemblerLabel jmp
, ARMv7Assembler::JumpType type
, ARMv7Assembler::Condition condition
= ARMv7Assembler::ConditionInvalid
)
451 , m_condition(condition
)
455 Jump(AssemblerLabel jmp
, SH4Assembler::JumpType type
= SH4Assembler::JumpFar
)
461 Jump(AssemblerLabel jmp
)
467 void link(AbstractMacroAssembler
<AssemblerType
>* masm
) const
470 masm
->m_assembler
.linkJump(m_label
, masm
->m_assembler
.label(), m_type
, m_condition
);
472 masm
->m_assembler
.linkJump(m_label
, masm
->m_assembler
.label(), m_type
);
474 masm
->m_assembler
.linkJump(m_label
, masm
->m_assembler
.label());
478 void linkTo(Label label
, AbstractMacroAssembler
<AssemblerType
>* masm
) const
481 masm
->m_assembler
.linkJump(m_label
, label
.m_label
, m_type
, m_condition
);
483 masm
->m_assembler
.linkJump(m_label
, label
.m_label
);
487 bool isSet() const { return m_label
.isSet(); }
490 AssemblerLabel m_label
;
492 ARMv7Assembler::JumpType m_type
;
493 ARMv7Assembler::Condition m_condition
;
496 SH4Assembler::JumpType m_type
;
500 struct PatchableJump
{
505 explicit PatchableJump(Jump jump
)
510 operator Jump
&() { return m_jump
; }
517 // A JumpList is a set of Jump objects.
518 // All jumps in the set will be linked to the same destination.
520 friend class LinkBuffer
;
523 typedef Vector
<Jump
, 16> JumpVector
;
525 void link(AbstractMacroAssembler
<AssemblerType
>* masm
)
527 size_t size
= m_jumps
.size();
528 for (size_t i
= 0; i
< size
; ++i
)
529 m_jumps
[i
].link(masm
);
533 void linkTo(Label label
, AbstractMacroAssembler
<AssemblerType
>* masm
)
535 size_t size
= m_jumps
.size();
536 for (size_t i
= 0; i
< size
; ++i
)
537 m_jumps
[i
].linkTo(label
, masm
);
541 void append(Jump jump
)
543 m_jumps
.append(jump
);
546 void append(JumpList
& other
)
548 m_jumps
.append(other
.m_jumps
.begin(), other
.m_jumps
.size());
553 return !m_jumps
.size();
561 const JumpVector
& jumps() { return m_jumps
; }
568 // Section 3: Misc admin methods
576 m_assembler
.align(16);
580 template<typename T
, typename U
>
581 static ptrdiff_t differenceBetween(T from
, U to
)
583 return AssemblerType::getDifferenceBetweenLabels(from
.m_label
, to
.m_label
);
586 static ptrdiff_t differenceBetweenCodePtr(const MacroAssemblerCodePtr
& a
, const MacroAssemblerCodePtr
& b
)
588 return reinterpret_cast<ptrdiff_t>(b
.executableAddress()) - reinterpret_cast<ptrdiff_t>(a
.executableAddress());
591 unsigned debugOffset() { return m_assembler
.debugOffset(); }
593 ALWAYS_INLINE
static void cacheFlush(void* code
, size_t size
)
595 AssemblerType::cacheFlush(code
, size
);
598 AbstractMacroAssembler()
599 : m_randomSource(cryptographicallyRandomNumber())
603 AssemblerType m_assembler
;
607 return m_randomSource
.getUint32();
610 WeakRandom m_randomSource
;
612 #if ENABLE(JIT_CONSTANT_BLINDING)
613 static bool scratchRegisterForBlinding() { return false; }
614 static bool shouldBlindForSpecificArch(uint32_t) { return true; }
615 static bool shouldBlindForSpecificArch(uint64_t) { return true; }
618 friend class LinkBuffer
;
619 friend class RepatchBuffer
;
621 static void linkJump(void* code
, Jump jump
, CodeLocationLabel target
)
623 AssemblerType::linkJump(code
, jump
.m_label
, target
.dataLocation());
626 static void linkPointer(void* code
, AssemblerLabel label
, void* value
)
628 AssemblerType::linkPointer(code
, label
, value
);
631 static void* getLinkerAddress(void* code
, AssemblerLabel label
)
633 return AssemblerType::getRelocatedAddress(code
, label
);
636 static unsigned getLinkerCallReturnOffset(Call call
)
638 return AssemblerType::getCallReturnOffset(call
.m_label
);
641 static void repatchJump(CodeLocationJump jump
, CodeLocationLabel destination
)
643 AssemblerType::relinkJump(jump
.dataLocation(), destination
.dataLocation());
646 static void repatchNearCall(CodeLocationNearCall nearCall
, CodeLocationLabel destination
)
648 AssemblerType::relinkCall(nearCall
.dataLocation(), destination
.executableAddress());
651 static void repatchCompact(CodeLocationDataLabelCompact dataLabelCompact
, int32_t value
)
653 AssemblerType::repatchCompact(dataLabelCompact
.dataLocation(), value
);
656 static void repatchInt32(CodeLocationDataLabel32 dataLabel32
, int32_t value
)
658 AssemblerType::repatchInt32(dataLabel32
.dataLocation(), value
);
661 static void repatchPointer(CodeLocationDataLabelPtr dataLabelPtr
, void* value
)
663 AssemblerType::repatchPointer(dataLabelPtr
.dataLocation(), value
);
666 static void* readPointer(CodeLocationDataLabelPtr dataLabelPtr
)
668 return AssemblerType::readPointer(dataLabelPtr
.dataLocation());
671 static void unreachableForPlatform()
674 #pragma clang diagnostic push
675 #pragma clang diagnostic ignored "-Wmissing-noreturn"
676 ASSERT_NOT_REACHED();
677 #pragma clang diagnostic pop
679 ASSERT_NOT_REACHED();
686 #endif // ENABLE(ASSEMBLER)
688 #endif // AbstractMacroAssembler_h