5#ifndef RUNTIME_VM_COMPILER_ASSEMBLER_ASSEMBLER_BASE_H_
6#define RUNTIME_VM_COMPILER_ASSEMBLER_ASSEMBLER_BASE_H_
8#if defined(DART_PRECOMPILED_RUNTIME)
9#error "AOT runtime should not use compiler sources (including header files)"
23#if defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_ARM64) || \
24 defined(TARGET_ARCH_RISCV32) || defined(TARGET_ARCH_RISCV64)
33#if defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_ARM64)
50 LRState(
const LRState&) =
default;
51 LRState& operator=(
const LRState&) =
default;
53 bool LRContainsReturnAddress()
const {
55 return (state_ & kLRContainsReturnAddressMask) != 0;
58 LRState SetLRContainsReturnAddress(
bool v)
const {
60 return LRState(frames_, v ? (state_ | 1) : (state_ & ~1));
65 LRState EnterFrame()
const {
68 constexpr auto kMaxFrames = (
sizeof(state_) * kBitsPerByte) - 1;
71 return LRState(frames_ + 1, state_ << 1);
78 LRState LeaveFrame()
const {
81 return LRState(frames_ - 1, state_ >> 1);
84 bool IsUnknown()
const {
return *
this == Unknown(); }
86 static LRState Unknown() {
return LRState(kUnknownMarker, kUnknownMarker); }
88 static LRState OnEntry() {
return LRState(0, 1); }
90 static LRState Clobbered() {
return LRState(0, 0); }
93 return frames_ == other.frames_ && state_ == other.state_;
97 LRState(uint8_t frames, uint8_t
state) : frames_(frames), state_(
state) {}
100 static constexpr uint8_t kLRContainsReturnAddressMask = 1;
102 static constexpr uint8_t kUnknownMarker = 0xFF;
116#define READS_RETURN_ADDRESS_FROM_LR(block) \
118 RELEASE_ASSERT(__ lr_state().LRContainsReturnAddress()); \
119 constexpr Register LR = LR_DO_NOT_USE_DIRECTLY; \
127#define WRITES_RETURN_ADDRESS_TO_LR(block) READS_RETURN_ADDRESS_FROM_LR(block)
131#define CLOBBERS_LR(block) \
133 RELEASE_ASSERT(!(__ lr_state().LRContainsReturnAddress())); \
134 constexpr Register LR = LR_DO_NOT_USE_DIRECTLY; \
142#define SPILLS_RETURN_ADDRESS_FROM_LR_TO_REGISTER(block) \
144 READS_RETURN_ADDRESS_FROM_LR(block); \
145 __ set_lr_state(__ lr_state().SetLRContainsReturnAddress(false)); \
151#define RESTORES_RETURN_ADDRESS_FROM_REGISTER_TO_LR(block) \
153 CLOBBERS_LR(block); \
154 __ set_lr_state(__ lr_state().SetLRContainsReturnAddress(true)); \
160#define SPILLS_LR_TO_FRAME(block) \
162 constexpr Register LR = LR_DO_NOT_USE_DIRECTLY; \
165 __ set_lr_state(__ lr_state().EnterFrame()); \
172#define RESTORES_LR_FROM_FRAME(block) \
174 CLOBBERS_LR(block); \
175 __ set_lr_state(__ lr_state().LeaveFrame()); \
197#if defined(HAS_SMI_63_BITS)
205#if defined(TARGET_ARCH_IS_64_BIT)
218#if defined(TARGET_ARCH_RISCV32) || defined(TARGET_ARCH_RISCV64)
232 bool IsBound()
const {
return position_ != -1; }
235 return unresolved_cb_ != -1 || unresolved_cj_ != -1 ||
236 unresolved_b_ != -1 || unresolved_j_ != -1 || unresolved_far_ != -1;
240 int32_t position_ = -1;
241 void BindTo(intptr_t position) {
244 position_ = position;
252#define DEFINE_BRANCH_CLASS(name) \
253 int32_t unresolved_##name##_ = -1; \
254 int32_t link_##name(int32_t position) { \
255 ASSERT(position > unresolved_##name##_); \
257 if (unresolved_##name##_ == -1) { \
260 offset = position - unresolved_##name##_; \
261 ASSERT(offset > 0); \
263 unresolved_##name##_ = position; \
266 DEFINE_BRANCH_CLASS(cb);
267 DEFINE_BRANCH_CLASS(cj);
268 DEFINE_BRANCH_CLASS(
b);
269 DEFINE_BRANCH_CLASS(j);
270 DEFINE_BRANCH_CLASS(far);
272 friend class MicroAssembler;
278 Label() : position_(0), unresolved_(0) {
280 for (
int i = 0; i < kMaxUnresolvedBranches; i++) {
281 unresolved_near_positions_[i] = -1;
296 return IsBound() ? -position_ - kBias : position_ - kBias;
301 return position_ - kBias;
306 return unresolved_near_positions_[--unresolved_];
309 bool IsBound()
const {
return position_ < 0; }
310 bool IsUnused()
const {
return position_ == 0 && unresolved_ == 0; }
312 bool HasNear()
const {
return unresolved_ != 0; }
315#if defined(TARGET_ARCH_X64) || defined(TARGET_ARCH_IA32)
316 static constexpr int kMaxUnresolvedBranches = 20;
318 static constexpr int kMaxUnresolvedBranches = 1;
325 static constexpr int kBias = 4;
328 intptr_t unresolved_;
329 intptr_t unresolved_near_positions_[kMaxUnresolvedBranches];
330#if defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_ARM64)
335 LRState lr_state_ = LRState::Unknown();
337 void UpdateLRState(LRState new_state) {
338 if (lr_state_.IsUnknown()) {
339 lr_state_ = new_state;
346 void Reinitialize() { position_ = 0; }
348#if defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_ARM64)
349 void BindTo(intptr_t position, LRState lr_state)
351 void BindTo(intptr_t position)
356 position_ = -position - kBias;
358#if defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_ARM64)
359 UpdateLRState(lr_state);
363#if defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_ARM64)
364 void LinkTo(intptr_t position, LRState lr_state)
366 void LinkTo(intptr_t position)
370 position_ = position + kBias;
372#if defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_ARM64)
373 UpdateLRState(lr_state);
377 void NearLinkTo(intptr_t position) {
379 ASSERT(unresolved_ < kMaxUnresolvedBranches);
380 unresolved_near_positions_[unresolved_++] = position;
401 const uword address_;
422 void set_previous(AssemblerFixup* previous) { previous_ = previous; }
424 intptr_t position()
const {
return position_; }
425 void set_position(intptr_t position) { position_ = position; }
437 template <
typename T>
440#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64) || \
441 defined(TARGET_ARCH_RISCV32) || defined(TARGET_ARCH_RISCV64)
447 *
reinterpret_cast<T*
>(cursor_) =
value;
449 cursor_ +=
sizeof(
T);
452 template <
typename T>
454 ASSERT(
Size() >=
static_cast<intptr_t
>(
sizeof(
T)));
455 cursor_ -=
sizeof(
T);
461 template <
typename T>
464 position <= (
Size() -
static_cast<intptr_t
>(
sizeof(
T))));
465#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64) || \
466 defined(TARGET_ARCH_RISCV32) || defined(TARGET_ARCH_RISCV64)
472 return *
reinterpret_cast<T*
>(contents_ + position);
476 template <
typename T>
479 position <= (
Size() -
static_cast<intptr_t
>(
sizeof(
T))));
480#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64) || \
481 defined(TARGET_ARCH_RISCV32) || defined(TARGET_ARCH_RISCV64)
487 *
reinterpret_cast<T*
>(contents_ + position) =
value;
493 ASSERT(fixups_processed_);
495 return *pointer_offsets_;
498#if defined(TARGET_ARCH_IA32)
500 void EmitObject(
const Object&
object);
505 fixup->set_previous(fixup_);
506 fixup->set_position(
Size());
515 intptr_t
Size()
const {
return cursor_ - contents_; }
540 intptr_t ComputeGap() {
return buffer_->Capacity() - buffer_->
Size(); }
543 bool has_ensured_capacity_;
562 void Reset() { cursor_ = contents_; }
568 static constexpr intptr_t kMinimumGap = 32;
576 bool fixups_processed_;
579 uword cursor()
const {
return cursor_; }
580 uword limit()
const {
return limit_; }
581 intptr_t Capacity()
const {
582 ASSERT(limit_ >= contents_);
583 return (limit_ - contents_) + kMinimumGap;
587 void ProcessFixups(
const MemoryRegion& region);
592 return data + capacity - kMinimumGap;
595 void ExtendCapacity();
644#if defined(DART_COMPRESSED_POINTERS)
693 intptr_t instance_size,
708 target::Class::GetInstanceSize(cls), failure, distance,
751 Register offset_in_words_as_smi) = 0;
892#if defined(DART_COMPRESSED_POINTERS)
901 Register offset_in_words_as_smi) = 0;
1075#if !defined(TARGET_ARCH_IS_32_BIT)
1081#if defined(TARGET_ARCH_IS_32_BIT)
1151 bool can_be_null =
false) = 0;
1184 intptr_t pc_offset_;
1223 Stop(
"Expected Smi");
1279 intptr_t frame_size,
1280 bool preserve_registers);
1291 const bool preserve_registers_;
static void done(const char *config, const char *src, const char *srcOptions, const char *name)
static uint32_t hash(const SkShaderBase::GradientInfo &v)
static bool equals(T *a, T *b)
#define RELEASE_ASSERT(cond)
virtual void StoreRelease(Register src, const Address &address, OperandSize size=kWordBytes)=0
void LoadCompressedField(Register dst, const FieldAddress &address)
void LoadCompressedSmiField(Register dst, const FieldAddress &address)
bool has_monomorphic_entry() const
intptr_t CountPointerOffsets() const
virtual void TryAllocateObject(intptr_t cid, intptr_t instance_size, Label *failure, JumpDistance distance, Register instance_reg, Register temp)=0
void FinalizeHash(Register hash, Register scratch=TMP)
void UnrolledMemCopy(Register dst_base, intptr_t dst_offset, Register src_base, intptr_t src_offset, intptr_t size, Register temp)
void LoadCompressedSmi(Register dst, const Address &address)
virtual void StoreBarrier(Register object, Register value, CanBeSmi can_be_smi, Register scratch)=0
intptr_t CodeSize() const
virtual void LoadIndexedPayload(Register dst, Register base, int32_t offset, Register index, ScaleFactor scale, OperandSize sz=kWordBytes)=0
void StoreReleaseCompressedToOffset(Register src, Register base, int32_t offset=0)
virtual void FinalizeHashForSize(intptr_t bit_size, Register hash, Register scratch=TMP)=0
void StoreReleaseCompressed(Register src, const Address &address)
virtual void LoadFieldAddressForOffset(Register reg, Register base, int32_t offset)=0
void Untested(const char *message)
void TryAllocate(const Class &cls, Label *failure, JumpDistance distance, Register instance_reg, Register temp)
void Stop(const char *message)
void LoadCompressed(Register dst, const Address &address)
virtual void LoadInt64FromBoxOrSmi(Register result, Register value)=0
virtual void RangeCheck(Register value, Register temp, intptr_t low, intptr_t high, RangeCheckCondition condition, Label *target)=0
void LoadCompressedFieldFromOffset(Register dst, Register base, int32_t offset)
virtual void LoadInt32FromBoxOrSmi(Register result, Register value)=0
bool has_monomorphic_entry_
ObjectPoolBuilder & object_pool_builder()
virtual void CompareWords(Register reg1, Register reg2, intptr_t offset, Register count, Register temp, Label *equals)=0
void LoadCompressedSmiFromOffset(Register dst, Register base, int32_t offset)
void LoadCompressedSmiFieldFromOffset(Register dst, Register base, int32_t offset)
virtual void LslRegister(Register dst, Register shift)=0
void StoreReleaseToOffset(Register src, Register base, int32_t offset=0, OperandSize size=kWordBytes)
AssemblerBase(ObjectPoolBuilder *object_pool_builder)
intptr_t unchecked_entry_offset_
virtual void MoveRegister(Register dst, Register src)
void LoadWordFromBoxOrSmi(Register result, Register value)
void StoreIntoObjectNoBarrier(Register object, const Address &address, Register value, MemoryOrder memory_order=kRelaxedNonAtomic, OperandSize size=kWordBytes)
void StoreToSlot(Register src, Register base, const Slot &slot, CanBeSmi can_be_smi, MemoryOrder memory_order=kRelaxedNonAtomic, Register scratch=TMP)
void LoadAcquireFromOffset(Register dst, Register base, int32_t offset=0, OperandSize size=kWordBytes)
void LoadCompressedFieldAddressForRegOffset(Register address, Register instance, Register offset_in_words_as_smi)
intptr_t UncheckedEntryOffset() const
virtual void StoreFieldToOffset(Register src, Register base, int32_t offset, OperandSize sz=kWordBytes)
virtual void StoreIntoObjectOffsetNoBarrier(Register object, int32_t offset, Register value, MemoryOrder memory_order=kRelaxedNonAtomic, OperandSize size=kWordBytes)
uword CodeAddress(intptr_t offset)
virtual void SmiTag(Register r)=0
void BindUncheckedEntryPoint()
void LoadCompressedFromOffset(Register dst, Register base, int32_t offset)
const ZoneGrowableArray< intptr_t > & GetPointerOffsets() const
void LoadSmiFieldFromOffset(Register dst, Register base, int32_t offset)
virtual void LoadFieldAddressForRegOffset(Register address, Register instance, Register offset_in_words_as_smi)=0
void LoadField(Register dst, const FieldAddress &address, OperandSize sz=kWordBytes)
virtual void LoadAcquire(Register dst, const Address &address, OperandSize size=kWordBytes)=0
virtual void MoveAndSmiTagRegister(Register dst, Register src)
void FinalizeInstructions(const MemoryRegion ®ion)
void LoadIndexedCompressed(Register dst, Register base, int32_t offset, Register index)
void ExtendNonNegativeSmi(Register dst)
const GrowableArray< CodeComment * > & comments() const
void StoreCompressedIntoObject(Register object, const Address &address, Register value, CanBeSmi can_be_smi=kValueCanBeSmi, MemoryOrder memory_order=kRelaxedNonAtomic, Register scratch=TMP)
bool should_be_aligned() const
void LoadFromSlot(Register dst, Register base, const Slot &slot)
void static bool EmittingComments()
void StoreToSlotNoBarrier(Register src, Register base, const Slot &slot, MemoryOrder memory_order=kRelaxedNonAtomic)
virtual void BranchIfSmi(Register reg, Label *label, JumpDistance distance=kFarJump)=0
virtual void LoadFromOffset(Register dst, Register base, int32_t offset, OperandSize sz=kWordBytes)
virtual void CompareWithMemoryValue(Register value, Address address, OperandSize size=kWordBytes)=0
virtual void ExtendAndSmiTagValue(Register dst, Register src, OperandSize sz)
virtual void CompareImmediate(Register reg, target::word imm, OperandSize width=kWordBytes)=0
void StoreCompressedIntoObjectOffsetNoBarrier(Register object, int32_t offset, Register value, MemoryOrder memory_order=kRelaxedNonAtomic)
void LoadAcquireCompressedFromOffset(Register dst, Register base, int32_t offset)
virtual void ArithmeticShiftRightImmediate(Register reg, intptr_t shift)=0
void StoreObjectIntoObjectOffsetNoBarrier(Register object, int32_t offset, const Object &value, MemoryOrder memory_order=kRelaxedNonAtomic, OperandSize size=kWordBytes)
virtual void VerifyStoreNeedsNoWriteBarrier(Register object, Register value)=0
void LoadTypeClassId(Register dst, Register src)
intptr_t InsertAlignedRelocation(BSS::Relocation reloc)
virtual void CombineHashes(Register dst, Register other)=0
virtual void StoreIntoObjectOffset(Register object, int32_t offset, Register value, CanBeSmi can_be_smi=kValueCanBeSmi, MemoryOrder memory_order=kRelaxedNonAtomic, Register scratch=TMP, OperandSize size=kWordBytes)
virtual void LoadFieldFromOffset(Register dst, Register base, int32_t offset, OperandSize sz=kWordBytes)
virtual void AndRegisters(Register dst, Register src1, Register src2=kNoRegister)=0
void LoadAcquireCompressed(Register dst, const Address &address)
virtual void Load(Register dst, const Address &address, OperandSize sz=kWordBytes)=0
void mark_should_be_aligned()
void StoreCompressedObjectIntoObjectOffsetNoBarrier(Register object, int32_t offset, const Object &value, MemoryOrder memory_order=kRelaxedNonAtomic)
virtual void Bind(Label *label)=0
virtual void ExtendValue(Register dst, Register src, OperandSize sz)=0
void StoreCompressedIntoObjectNoBarrier(Register object, const Address &address, Register value, MemoryOrder memory_order=kRelaxedNonAtomic)
virtual void StoreObjectIntoObjectNoBarrier(Register object, const Address &address, const Object &value, MemoryOrder memory_order=kRelaxedNonAtomic, OperandSize size=kWordBytes)=0
void StoreCompressedIntoObjectOffset(Register object, int32_t offset, Register value, CanBeSmi can_be_smi=kValueCanBeSmi, MemoryOrder memory_order=kRelaxedNonAtomic, Register scratch=TMP)
virtual void ArrayStoreBarrier(Register object, Register slot, Register value, CanBeSmi can_be_smi, Register scratch)=0
void LoadSmi(Register dst, const Address &address)
virtual void StoreCompressedObjectIntoObjectNoBarrier(Register object, const Address &address, const Object &value, MemoryOrder memory_order=kRelaxedNonAtomic)
bool HasObjectPoolBuilder() const
virtual void StoreToOffset(Register src, Register base, int32_t offset, OperandSize sz=kWordBytes)
void LoadAbstractTypeNullability(Register dst, Register type)
virtual void LsrImmediate(Register dst, int32_t shift)=0
void LoadSmiFromOffset(Register dst, Register base, int32_t offset)
virtual void AndImmediate(Register dst, target::word imm)=0
void StoreIntoArray(Register object, Register slot, Register value, CanBeSmi can_value_be_smi=kValueCanBeSmi, Register scratch=TMP, OperandSize size=kWordBytes)
void StoreCompressedIntoArray(Register object, Register slot, Register value, CanBeSmi can_value_be_smi=kValueCanBeSmi, Register scratch=TMP)
void LoadSmiField(Register dst, const FieldAddress &address)
void Comment(const char *format,...) PRINTF_ATTRIBUTE(2
void StoreIntoObject(Register object, const Address &address, Register value, CanBeSmi can_be_smi=kValueCanBeSmi, MemoryOrder memory_order=kRelaxedNonAtomic, Register scratch=TMP, OperandSize size=kWordBytes)
virtual void MulImmediate(Register dst, target::word imm, OperandSize=kWordBytes)=0
virtual void EnsureHasClassIdInDEBUG(intptr_t cid, Register src, Register scratch, bool can_be_null=false)=0
void MsanUnpoison(Register base, intptr_t length_in_bytes)
void VerifySmi(Register dst)
void CompareAbstractTypeNullabilityWith(Register type, int8_t value, Register scratch)
void Unreachable(const char *message)
intptr_t prologue_offset() const
virtual void LoadImmediate(Register dst, target::word imm)=0
void Unimplemented(const char *message)
virtual void Store(Register src, const Address &address, OperandSize sz=kWordBytes)=0
EnsureCapacity(AssemblerBuffer *buffer)
void Store(intptr_t position, T value)
void EmitFixup(AssemblerFixup *fixup)
const ZoneGrowableArray< intptr_t > & pointer_offsets() const
bool HasEnsuredCapacity() const
T Load(intptr_t position)
void FinalizeInstructions(const MemoryRegion ®ion)
intptr_t CountPointerOffsets() const
intptr_t GetPosition() const
uword Address(intptr_t position)
virtual bool IsPointerOffset() const =0
virtual ~AssemblerFixup()
virtual void Process(const MemoryRegion ®ion, intptr_t position)=0
ExternalLabel(uword address)
intptr_t LinkPosition() const
intptr_t Position() const
LeafRuntimeScope(Assembler *assembler, intptr_t frame_size, bool preserve_registers)
void Call(const RuntimeEntry &entry, intptr_t argument_count)
bool operator==(const FlutterPoint &a, const FlutterPoint &b)
static const uint8_t buffer[]
uint32_t uint32_t * format
#define DECLARE_FLAG(type, name)
constexpr OperandSize kWordBytes
constexpr intptr_t kBitsPerInt32
static T LoadUnaligned(const T *ptr)
static void StoreUnaligned(T *ptr, T value)
static int8_t data[kExtLength]