1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #ifndef V8_ARM64_ASSEMBLER_ARM64_INL_H_
6 #define V8_ARM64_ASSEMBLER_ARM64_INL_H_
8 #include "src/arm64/assembler-arm64.h"
9 #include "src/assembler.h"
10 #include "src/debug.h"
17 bool CpuFeatures::SupportsCrankshaft() { return true; }
18 bool CpuFeatures::SupportsSIMD128InCrankshaft() { return false; }
21 void RelocInfo::apply(intptr_t delta, ICacheFlushMode icache_flush_mode) {
26 void RelocInfo::set_target_address(Address target,
27 WriteBarrierMode write_barrier_mode,
28 ICacheFlushMode icache_flush_mode) {
29 DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_));
30 Assembler::set_target_address_at(pc_, host_, target, icache_flush_mode);
31 if (write_barrier_mode == UPDATE_WRITE_BARRIER && host() != NULL &&
32 IsCodeTarget(rmode_)) {
33 Object* target_code = Code::GetCodeFromTargetAddress(target);
34 host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(
35 host(), this, HeapObject::cast(target_code));
40 inline unsigned CPURegister::code() const {
46 inline CPURegister::RegisterType CPURegister::type() const {
47 DCHECK(IsValidOrNone());
52 inline RegList CPURegister::Bit() const {
53 DCHECK(reg_code < (sizeof(RegList) * kBitsPerByte));
54 return IsValid() ? 1UL << reg_code : 0;
58 inline unsigned CPURegister::SizeInBits() const {
64 inline int CPURegister::SizeInBytes() const {
66 DCHECK(SizeInBits() % 8 == 0);
71 inline bool CPURegister::Is32Bits() const {
73 return reg_size == 32;
77 inline bool CPURegister::Is64Bits() const {
79 return reg_size == 64;
83 inline bool CPURegister::IsValid() const {
84 if (IsValidRegister() || IsValidFPRegister()) {
94 inline bool CPURegister::IsValidRegister() const {
95 return IsRegister() &&
96 ((reg_size == kWRegSizeInBits) || (reg_size == kXRegSizeInBits)) &&
97 ((reg_code < kNumberOfRegisters) || (reg_code == kSPRegInternalCode));
101 inline bool CPURegister::IsValidFPRegister() const {
102 return IsFPRegister() &&
103 ((reg_size == kSRegSizeInBits) || (reg_size == kDRegSizeInBits)) &&
104 (reg_code < kNumberOfFPRegisters);
108 inline bool CPURegister::IsNone() const {
109 // kNoRegister types should always have size 0 and code 0.
110 DCHECK((reg_type != kNoRegister) || (reg_code == 0));
111 DCHECK((reg_type != kNoRegister) || (reg_size == 0));
113 return reg_type == kNoRegister;
117 inline bool CPURegister::Is(const CPURegister& other) const {
118 DCHECK(IsValidOrNone() && other.IsValidOrNone());
119 return Aliases(other) && (reg_size == other.reg_size);
123 inline bool CPURegister::Aliases(const CPURegister& other) const {
124 DCHECK(IsValidOrNone() && other.IsValidOrNone());
125 return (reg_code == other.reg_code) && (reg_type == other.reg_type);
129 inline bool CPURegister::IsRegister() const {
130 return reg_type == kRegister;
134 inline bool CPURegister::IsFPRegister() const {
135 return reg_type == kFPRegister;
139 inline bool CPURegister::IsSameSizeAndType(const CPURegister& other) const {
140 return (reg_size == other.reg_size) && (reg_type == other.reg_type);
144 inline bool CPURegister::IsValidOrNone() const {
145 return IsValid() || IsNone();
149 inline bool CPURegister::IsZero() const {
151 return IsRegister() && (reg_code == kZeroRegCode);
155 inline bool CPURegister::IsSP() const {
157 return IsRegister() && (reg_code == kSPRegInternalCode);
161 inline void CPURegList::Combine(const CPURegList& other) {
163 DCHECK(other.type() == type_);
164 DCHECK(other.RegisterSizeInBits() == size_);
165 list_ |= other.list();
169 inline void CPURegList::Remove(const CPURegList& other) {
171 if (other.type() == type_) {
172 list_ &= ~other.list();
177 inline void CPURegList::Combine(const CPURegister& other) {
178 DCHECK(other.type() == type_);
179 DCHECK(other.SizeInBits() == size_);
180 Combine(other.code());
184 inline void CPURegList::Remove(const CPURegister& other1,
185 const CPURegister& other2,
186 const CPURegister& other3,
187 const CPURegister& other4) {
188 if (!other1.IsNone() && (other1.type() == type_)) Remove(other1.code());
189 if (!other2.IsNone() && (other2.type() == type_)) Remove(other2.code());
190 if (!other3.IsNone() && (other3.type() == type_)) Remove(other3.code());
191 if (!other4.IsNone() && (other4.type() == type_)) Remove(other4.code());
195 inline void CPURegList::Combine(int code) {
197 DCHECK(CPURegister::Create(code, size_, type_).IsValid());
198 list_ |= (1UL << code);
202 inline void CPURegList::Remove(int code) {
204 DCHECK(CPURegister::Create(code, size_, type_).IsValid());
205 list_ &= ~(1UL << code);
209 inline Register Register::XRegFromCode(unsigned code) {
210 if (code == kSPRegInternalCode) {
213 DCHECK(code < kNumberOfRegisters);
214 return Register::Create(code, kXRegSizeInBits);
219 inline Register Register::WRegFromCode(unsigned code) {
220 if (code == kSPRegInternalCode) {
223 DCHECK(code < kNumberOfRegisters);
224 return Register::Create(code, kWRegSizeInBits);
229 inline FPRegister FPRegister::SRegFromCode(unsigned code) {
230 DCHECK(code < kNumberOfFPRegisters);
231 return FPRegister::Create(code, kSRegSizeInBits);
235 inline FPRegister FPRegister::DRegFromCode(unsigned code) {
236 DCHECK(code < kNumberOfFPRegisters);
237 return FPRegister::Create(code, kDRegSizeInBits);
241 inline Register CPURegister::W() const {
242 DCHECK(IsValidRegister());
243 return Register::WRegFromCode(reg_code);
247 inline Register CPURegister::X() const {
248 DCHECK(IsValidRegister());
249 return Register::XRegFromCode(reg_code);
253 inline FPRegister CPURegister::S() const {
254 DCHECK(IsValidFPRegister());
255 return FPRegister::SRegFromCode(reg_code);
259 inline FPRegister CPURegister::D() const {
260 DCHECK(IsValidFPRegister());
261 return FPRegister::DRegFromCode(reg_code);
266 // Default initializer is for int types
268 struct ImmediateInitializer {
269 static const bool kIsIntType = true;
270 static inline RelocInfo::Mode rmode_for(T) {
271 return sizeof(T) == 8 ? RelocInfo::NONE64 : RelocInfo::NONE32;
273 static inline int64_t immediate_for(T t) {
274 STATIC_ASSERT(sizeof(T) <= 8);
281 struct ImmediateInitializer<Smi*> {
282 static const bool kIsIntType = false;
283 static inline RelocInfo::Mode rmode_for(Smi* t) {
284 return RelocInfo::NONE64;
286 static inline int64_t immediate_for(Smi* t) {;
287 return reinterpret_cast<int64_t>(t);
293 struct ImmediateInitializer<ExternalReference> {
294 static const bool kIsIntType = false;
295 static inline RelocInfo::Mode rmode_for(ExternalReference t) {
296 return RelocInfo::EXTERNAL_REFERENCE;
298 static inline int64_t immediate_for(ExternalReference t) {;
299 return reinterpret_cast<int64_t>(t.address());
305 Immediate::Immediate(Handle<T> value) {
306 InitializeHandle(value);
311 Immediate::Immediate(T t)
312 : value_(ImmediateInitializer<T>::immediate_for(t)),
313 rmode_(ImmediateInitializer<T>::rmode_for(t)) {}
317 Immediate::Immediate(T t, RelocInfo::Mode rmode)
318 : value_(ImmediateInitializer<T>::immediate_for(t)),
320 STATIC_ASSERT(ImmediateInitializer<T>::kIsIntType);
326 Operand::Operand(Handle<T> value) : immediate_(value), reg_(NoReg) {}
330 Operand::Operand(T t) : immediate_(t), reg_(NoReg) {}
334 Operand::Operand(T t, RelocInfo::Mode rmode)
335 : immediate_(t, rmode),
339 Operand::Operand(Register reg, Shift shift, unsigned shift_amount)
344 shift_amount_(shift_amount) {
345 DCHECK(reg.Is64Bits() || (shift_amount < kWRegSizeInBits));
346 DCHECK(reg.Is32Bits() || (shift_amount < kXRegSizeInBits));
351 Operand::Operand(Register reg, Extend extend, unsigned shift_amount)
356 shift_amount_(shift_amount) {
357 DCHECK(reg.IsValid());
358 DCHECK(shift_amount <= 4);
361 // Extend modes SXTX and UXTX require a 64-bit register.
362 DCHECK(reg.Is64Bits() || ((extend != SXTX) && (extend != UXTX)));
366 bool Operand::IsImmediate() const {
367 return reg_.Is(NoReg);
371 bool Operand::IsShiftedRegister() const {
372 return reg_.IsValid() && (shift_ != NO_SHIFT);
376 bool Operand::IsExtendedRegister() const {
377 return reg_.IsValid() && (extend_ != NO_EXTEND);
381 bool Operand::IsZero() const {
383 return ImmediateValue() == 0;
385 return reg().IsZero();
390 Operand Operand::ToExtendedRegister() const {
391 DCHECK(IsShiftedRegister());
392 DCHECK((shift_ == LSL) && (shift_amount_ <= 4));
393 return Operand(reg_, reg_.Is64Bits() ? UXTX : UXTW, shift_amount_);
397 Immediate Operand::immediate() const {
398 DCHECK(IsImmediate());
403 int64_t Operand::ImmediateValue() const {
404 DCHECK(IsImmediate());
405 return immediate_.value();
409 Register Operand::reg() const {
410 DCHECK(IsShiftedRegister() || IsExtendedRegister());
415 Shift Operand::shift() const {
416 DCHECK(IsShiftedRegister());
421 Extend Operand::extend() const {
422 DCHECK(IsExtendedRegister());
427 unsigned Operand::shift_amount() const {
428 DCHECK(IsShiftedRegister() || IsExtendedRegister());
429 return shift_amount_;
433 Operand Operand::UntagSmi(Register smi) {
434 STATIC_ASSERT(kXRegSizeInBits == static_cast<unsigned>(kSmiShift +
436 DCHECK(smi.Is64Bits());
437 return Operand(smi, ASR, kSmiShift);
441 Operand Operand::UntagSmiAndScale(Register smi, int scale) {
442 STATIC_ASSERT(kXRegSizeInBits == static_cast<unsigned>(kSmiShift +
444 DCHECK(smi.Is64Bits());
445 DCHECK((scale >= 0) && (scale <= (64 - kSmiValueSize)));
446 if (scale > kSmiShift) {
447 return Operand(smi, LSL, scale - kSmiShift);
448 } else if (scale < kSmiShift) {
449 return Operand(smi, ASR, kSmiShift - scale);
455 MemOperand::MemOperand()
456 : base_(NoReg), regoffset_(NoReg), offset_(0), addrmode_(Offset),
457 shift_(NO_SHIFT), extend_(NO_EXTEND), shift_amount_(0) {
461 MemOperand::MemOperand(Register base, int64_t offset, AddrMode addrmode)
462 : base_(base), regoffset_(NoReg), offset_(offset), addrmode_(addrmode),
463 shift_(NO_SHIFT), extend_(NO_EXTEND), shift_amount_(0) {
464 DCHECK(base.Is64Bits() && !base.IsZero());
468 MemOperand::MemOperand(Register base,
471 unsigned shift_amount)
472 : base_(base), regoffset_(regoffset), offset_(0), addrmode_(Offset),
473 shift_(NO_SHIFT), extend_(extend), shift_amount_(shift_amount) {
474 DCHECK(base.Is64Bits() && !base.IsZero());
475 DCHECK(!regoffset.IsSP());
476 DCHECK((extend == UXTW) || (extend == SXTW) || (extend == SXTX));
478 // SXTX extend mode requires a 64-bit offset register.
479 DCHECK(regoffset.Is64Bits() || (extend != SXTX));
483 MemOperand::MemOperand(Register base,
486 unsigned shift_amount)
487 : base_(base), regoffset_(regoffset), offset_(0), addrmode_(Offset),
488 shift_(shift), extend_(NO_EXTEND), shift_amount_(shift_amount) {
489 DCHECK(base.Is64Bits() && !base.IsZero());
490 DCHECK(regoffset.Is64Bits() && !regoffset.IsSP());
491 DCHECK(shift == LSL);
495 MemOperand::MemOperand(Register base, const Operand& offset, AddrMode addrmode)
496 : base_(base), addrmode_(addrmode) {
497 DCHECK(base.Is64Bits() && !base.IsZero());
499 if (offset.IsImmediate()) {
500 offset_ = offset.ImmediateValue();
503 } else if (offset.IsShiftedRegister()) {
504 DCHECK(addrmode == Offset);
506 regoffset_ = offset.reg();
507 shift_ = offset.shift();
508 shift_amount_ = offset.shift_amount();
513 // These assertions match those in the shifted-register constructor.
514 DCHECK(regoffset_.Is64Bits() && !regoffset_.IsSP());
515 DCHECK(shift_ == LSL);
517 DCHECK(offset.IsExtendedRegister());
518 DCHECK(addrmode == Offset);
520 regoffset_ = offset.reg();
521 extend_ = offset.extend();
522 shift_amount_ = offset.shift_amount();
527 // These assertions match those in the extended-register constructor.
528 DCHECK(!regoffset_.IsSP());
529 DCHECK((extend_ == UXTW) || (extend_ == SXTW) || (extend_ == SXTX));
530 DCHECK((regoffset_.Is64Bits() || (extend_ != SXTX)));
534 bool MemOperand::IsImmediateOffset() const {
535 return (addrmode_ == Offset) && regoffset_.Is(NoReg);
539 bool MemOperand::IsRegisterOffset() const {
540 return (addrmode_ == Offset) && !regoffset_.Is(NoReg);
544 bool MemOperand::IsPreIndex() const {
545 return addrmode_ == PreIndex;
549 bool MemOperand::IsPostIndex() const {
550 return addrmode_ == PostIndex;
553 Operand MemOperand::OffsetAsOperand() const {
554 if (IsImmediateOffset()) {
557 DCHECK(IsRegisterOffset());
558 if (extend() == NO_EXTEND) {
559 return Operand(regoffset(), shift(), shift_amount());
561 return Operand(regoffset(), extend(), shift_amount());
567 void Assembler::Unreachable() {
569 debug("UNREACHABLE", __LINE__, BREAK);
571 // Crash by branching to 0. lr now points near the fault.
577 Address Assembler::target_pointer_address_at(Address pc) {
578 Instruction* instr = reinterpret_cast<Instruction*>(pc);
579 DCHECK(instr->IsLdrLiteralX());
580 return reinterpret_cast<Address>(instr->ImmPCOffsetTarget());
584 // Read/Modify the code target address in the branch/call instruction at pc.
585 Address Assembler::target_address_at(Address pc,
586 ConstantPoolArray* constant_pool) {
587 return Memory::Address_at(target_pointer_address_at(pc));
591 Address Assembler::target_address_at(Address pc, Code* code) {
592 ConstantPoolArray* constant_pool = code ? code->constant_pool() : NULL;
593 return target_address_at(pc, constant_pool);
597 Address Assembler::target_address_from_return_address(Address pc) {
598 // Returns the address of the call target from the return address that will
599 // be returned to after a call.
600 // Call sequence on ARM64 is:
601 // ldr ip0, #... @ load from literal pool
603 Address candidate = pc - 2 * kInstructionSize;
604 Instruction* instr = reinterpret_cast<Instruction*>(candidate);
606 DCHECK(instr->IsLdrLiteralX());
611 Address Assembler::break_address_from_return_address(Address pc) {
612 return pc - Assembler::kPatchDebugBreakSlotReturnOffset;
616 Address Assembler::return_address_from_call_start(Address pc) {
617 // The call, generated by MacroAssembler::Call, is one of two possible
620 // Without relocation:
621 // movz temp, #(target & 0x000000000000ffff)
622 // movk temp, #(target & 0x00000000ffff0000)
623 // movk temp, #(target & 0x0000ffff00000000)
630 // The return address is immediately after the blr instruction in both cases,
631 // so it can be found by adding the call size to the address at the start of
632 // the call sequence.
633 STATIC_ASSERT(Assembler::kCallSizeWithoutRelocation == 4 * kInstructionSize);
634 STATIC_ASSERT(Assembler::kCallSizeWithRelocation == 2 * kInstructionSize);
636 Instruction* instr = reinterpret_cast<Instruction*>(pc);
637 if (instr->IsMovz()) {
638 // Verify the instruction sequence.
639 DCHECK(instr->following(1)->IsMovk());
640 DCHECK(instr->following(2)->IsMovk());
641 DCHECK(instr->following(3)->IsBranchAndLinkToRegister());
642 return pc + Assembler::kCallSizeWithoutRelocation;
644 // Verify the instruction sequence.
645 DCHECK(instr->IsLdrLiteralX());
646 DCHECK(instr->following(1)->IsBranchAndLinkToRegister());
647 return pc + Assembler::kCallSizeWithRelocation;
652 void Assembler::deserialization_set_special_target_at(
653 Address constant_pool_entry, Code* code, Address target) {
654 Memory::Address_at(constant_pool_entry) = target;
658 void Assembler::set_target_address_at(Address pc,
659 ConstantPoolArray* constant_pool,
661 ICacheFlushMode icache_flush_mode) {
662 Memory::Address_at(target_pointer_address_at(pc)) = target;
663 // Intuitively, we would think it is necessary to always flush the
664 // instruction cache after patching a target address in the code as follows:
665 // CpuFeatures::FlushICache(pc, sizeof(target));
666 // However, on ARM, an instruction is actually patched in the case of
667 // embedded constants of the form:
668 // ldr ip, [pc, #...]
669 // since the instruction accessing this address in the constant pool remains
670 // unchanged, a flush is not required.
674 void Assembler::set_target_address_at(Address pc,
677 ICacheFlushMode icache_flush_mode) {
678 ConstantPoolArray* constant_pool = code ? code->constant_pool() : NULL;
679 set_target_address_at(pc, constant_pool, target, icache_flush_mode);
683 int RelocInfo::target_address_size() {
688 Address RelocInfo::target_address() {
689 DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_));
690 return Assembler::target_address_at(pc_, host_);
694 Address RelocInfo::target_address_address() {
695 DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_)
696 || rmode_ == EMBEDDED_OBJECT
697 || rmode_ == EXTERNAL_REFERENCE);
698 return Assembler::target_pointer_address_at(pc_);
702 Address RelocInfo::constant_pool_entry_address() {
703 DCHECK(IsInConstantPool());
704 return Assembler::target_pointer_address_at(pc_);
708 Object* RelocInfo::target_object() {
709 DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
710 return reinterpret_cast<Object*>(Assembler::target_address_at(pc_, host_));
714 Handle<Object> RelocInfo::target_object_handle(Assembler* origin) {
715 DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
716 return Handle<Object>(reinterpret_cast<Object**>(
717 Assembler::target_address_at(pc_, host_)));
721 void RelocInfo::set_target_object(Object* target,
722 WriteBarrierMode write_barrier_mode,
723 ICacheFlushMode icache_flush_mode) {
724 DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
725 Assembler::set_target_address_at(pc_, host_,
726 reinterpret_cast<Address>(target),
728 if (write_barrier_mode == UPDATE_WRITE_BARRIER &&
730 target->IsHeapObject()) {
731 host()->GetHeap()->incremental_marking()->RecordWrite(
732 host(), &Memory::Object_at(pc_), HeapObject::cast(target));
737 Address RelocInfo::target_reference() {
738 DCHECK(rmode_ == EXTERNAL_REFERENCE);
739 return Assembler::target_address_at(pc_, host_);
743 Address RelocInfo::target_runtime_entry(Assembler* origin) {
744 DCHECK(IsRuntimeEntry(rmode_));
745 return target_address();
749 void RelocInfo::set_target_runtime_entry(Address target,
750 WriteBarrierMode write_barrier_mode,
751 ICacheFlushMode icache_flush_mode) {
752 DCHECK(IsRuntimeEntry(rmode_));
753 if (target_address() != target) {
754 set_target_address(target, write_barrier_mode, icache_flush_mode);
759 Handle<Cell> RelocInfo::target_cell_handle() {
761 Cell *null_cell = NULL;
762 return Handle<Cell>(null_cell);
766 Cell* RelocInfo::target_cell() {
767 DCHECK(rmode_ == RelocInfo::CELL);
768 return Cell::FromValueAddress(Memory::Address_at(pc_));
772 void RelocInfo::set_target_cell(Cell* cell,
773 WriteBarrierMode write_barrier_mode,
774 ICacheFlushMode icache_flush_mode) {
779 static const int kNoCodeAgeSequenceLength = 5 * kInstructionSize;
780 static const int kCodeAgeStubEntryOffset = 3 * kInstructionSize;
783 Handle<Object> RelocInfo::code_age_stub_handle(Assembler* origin) {
784 UNREACHABLE(); // This should never be reached on ARM64.
785 return Handle<Object>();
789 Code* RelocInfo::code_age_stub() {
790 DCHECK(rmode_ == RelocInfo::CODE_AGE_SEQUENCE);
791 // Read the stub entry point from the code age sequence.
792 Address stub_entry_address = pc_ + kCodeAgeStubEntryOffset;
793 return Code::GetCodeFromTargetAddress(Memory::Address_at(stub_entry_address));
797 void RelocInfo::set_code_age_stub(Code* stub,
798 ICacheFlushMode icache_flush_mode) {
799 DCHECK(rmode_ == RelocInfo::CODE_AGE_SEQUENCE);
800 DCHECK(!Code::IsYoungSequence(stub->GetIsolate(), pc_));
801 // Overwrite the stub entry point in the code age sequence. This is loaded as
802 // a literal so there is no need to call FlushICache here.
803 Address stub_entry_address = pc_ + kCodeAgeStubEntryOffset;
804 Memory::Address_at(stub_entry_address) = stub->instruction_start();
808 Address RelocInfo::call_address() {
809 DCHECK((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
810 (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
811 // For the above sequences the Relocinfo points to the load literal loading
813 return Assembler::target_address_at(pc_, host_);
817 void RelocInfo::set_call_address(Address target) {
818 DCHECK((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
819 (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
820 Assembler::set_target_address_at(pc_, host_, target);
821 if (host() != NULL) {
822 Object* target_code = Code::GetCodeFromTargetAddress(target);
823 host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(
824 host(), this, HeapObject::cast(target_code));
829 void RelocInfo::WipeOut() {
830 DCHECK(IsEmbeddedObject(rmode_) ||
831 IsCodeTarget(rmode_) ||
832 IsRuntimeEntry(rmode_) ||
833 IsExternalReference(rmode_));
834 Assembler::set_target_address_at(pc_, host_, NULL);
838 bool RelocInfo::IsPatchedReturnSequence() {
839 // The sequence must be:
840 // ldr ip0, [pc, #offset]
842 // See arm64/debug-arm64.cc BreakLocationIterator::SetDebugBreakAtReturn().
843 Instruction* i1 = reinterpret_cast<Instruction*>(pc_);
844 Instruction* i2 = i1->following();
845 return i1->IsLdrLiteralX() && (i1->Rt() == ip0.code()) &&
846 i2->IsBranchAndLinkToRegister() && (i2->Rn() == ip0.code());
850 bool RelocInfo::IsPatchedDebugBreakSlotSequence() {
851 Instruction* current_instr = reinterpret_cast<Instruction*>(pc_);
852 return !current_instr->IsNop(Assembler::DEBUG_BREAK_NOP);
856 void RelocInfo::Visit(Isolate* isolate, ObjectVisitor* visitor) {
857 RelocInfo::Mode mode = rmode();
858 if (mode == RelocInfo::EMBEDDED_OBJECT) {
859 visitor->VisitEmbeddedPointer(this);
860 } else if (RelocInfo::IsCodeTarget(mode)) {
861 visitor->VisitCodeTarget(this);
862 } else if (mode == RelocInfo::CELL) {
863 visitor->VisitCell(this);
864 } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
865 visitor->VisitExternalReference(this);
866 } else if (((RelocInfo::IsJSReturn(mode) &&
867 IsPatchedReturnSequence()) ||
868 (RelocInfo::IsDebugBreakSlot(mode) &&
869 IsPatchedDebugBreakSlotSequence())) &&
870 isolate->debug()->has_break_points()) {
871 visitor->VisitDebugTarget(this);
872 } else if (RelocInfo::IsRuntimeEntry(mode)) {
873 visitor->VisitRuntimeEntry(this);
878 template<typename StaticVisitor>
879 void RelocInfo::Visit(Heap* heap) {
880 RelocInfo::Mode mode = rmode();
881 if (mode == RelocInfo::EMBEDDED_OBJECT) {
882 StaticVisitor::VisitEmbeddedPointer(heap, this);
883 } else if (RelocInfo::IsCodeTarget(mode)) {
884 StaticVisitor::VisitCodeTarget(heap, this);
885 } else if (mode == RelocInfo::CELL) {
886 StaticVisitor::VisitCell(heap, this);
887 } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
888 StaticVisitor::VisitExternalReference(this);
889 } else if (heap->isolate()->debug()->has_break_points() &&
890 ((RelocInfo::IsJSReturn(mode) &&
891 IsPatchedReturnSequence()) ||
892 (RelocInfo::IsDebugBreakSlot(mode) &&
893 IsPatchedDebugBreakSlotSequence()))) {
894 StaticVisitor::VisitDebugTarget(heap, this);
895 } else if (RelocInfo::IsRuntimeEntry(mode)) {
896 StaticVisitor::VisitRuntimeEntry(this);
901 LoadStoreOp Assembler::LoadOpFor(const CPURegister& rt) {
902 DCHECK(rt.IsValid());
903 if (rt.IsRegister()) {
904 return rt.Is64Bits() ? LDR_x : LDR_w;
906 DCHECK(rt.IsFPRegister());
907 return rt.Is64Bits() ? LDR_d : LDR_s;
912 LoadStorePairOp Assembler::LoadPairOpFor(const CPURegister& rt,
913 const CPURegister& rt2) {
914 DCHECK(AreSameSizeAndType(rt, rt2));
916 if (rt.IsRegister()) {
917 return rt.Is64Bits() ? LDP_x : LDP_w;
919 DCHECK(rt.IsFPRegister());
920 return rt.Is64Bits() ? LDP_d : LDP_s;
925 LoadStoreOp Assembler::StoreOpFor(const CPURegister& rt) {
926 DCHECK(rt.IsValid());
927 if (rt.IsRegister()) {
928 return rt.Is64Bits() ? STR_x : STR_w;
930 DCHECK(rt.IsFPRegister());
931 return rt.Is64Bits() ? STR_d : STR_s;
936 LoadStorePairOp Assembler::StorePairOpFor(const CPURegister& rt,
937 const CPURegister& rt2) {
938 DCHECK(AreSameSizeAndType(rt, rt2));
940 if (rt.IsRegister()) {
941 return rt.Is64Bits() ? STP_x : STP_w;
943 DCHECK(rt.IsFPRegister());
944 return rt.Is64Bits() ? STP_d : STP_s;
949 LoadStorePairNonTemporalOp Assembler::LoadPairNonTemporalOpFor(
950 const CPURegister& rt, const CPURegister& rt2) {
951 DCHECK(AreSameSizeAndType(rt, rt2));
953 if (rt.IsRegister()) {
954 return rt.Is64Bits() ? LDNP_x : LDNP_w;
956 DCHECK(rt.IsFPRegister());
957 return rt.Is64Bits() ? LDNP_d : LDNP_s;
962 LoadStorePairNonTemporalOp Assembler::StorePairNonTemporalOpFor(
963 const CPURegister& rt, const CPURegister& rt2) {
964 DCHECK(AreSameSizeAndType(rt, rt2));
966 if (rt.IsRegister()) {
967 return rt.Is64Bits() ? STNP_x : STNP_w;
969 DCHECK(rt.IsFPRegister());
970 return rt.Is64Bits() ? STNP_d : STNP_s;
975 LoadLiteralOp Assembler::LoadLiteralOpFor(const CPURegister& rt) {
976 if (rt.IsRegister()) {
977 return rt.Is64Bits() ? LDR_x_lit : LDR_w_lit;
979 DCHECK(rt.IsFPRegister());
980 return rt.Is64Bits() ? LDR_d_lit : LDR_s_lit;
985 int Assembler::LinkAndGetInstructionOffsetTo(Label* label) {
986 DCHECK(kStartOfLabelLinkChain == 0);
987 int offset = LinkAndGetByteOffsetTo(label);
988 DCHECK(IsAligned(offset, kInstructionSize));
989 return offset >> kInstructionSizeLog2;
993 Instr Assembler::Flags(FlagsUpdate S) {
995 return 1 << FlagsUpdate_offset;
996 } else if (S == LeaveFlags) {
997 return 0 << FlagsUpdate_offset;
1004 Instr Assembler::Cond(Condition cond) {
1005 return cond << Condition_offset;
1009 Instr Assembler::ImmPCRelAddress(int imm21) {
1010 CHECK(is_int21(imm21));
1011 Instr imm = static_cast<Instr>(truncate_to_int21(imm21));
1012 Instr immhi = (imm >> ImmPCRelLo_width) << ImmPCRelHi_offset;
1013 Instr immlo = imm << ImmPCRelLo_offset;
1014 return (immhi & ImmPCRelHi_mask) | (immlo & ImmPCRelLo_mask);
1018 Instr Assembler::ImmUncondBranch(int imm26) {
1019 CHECK(is_int26(imm26));
1020 return truncate_to_int26(imm26) << ImmUncondBranch_offset;
1024 Instr Assembler::ImmCondBranch(int imm19) {
1025 CHECK(is_int19(imm19));
1026 return truncate_to_int19(imm19) << ImmCondBranch_offset;
1030 Instr Assembler::ImmCmpBranch(int imm19) {
1031 CHECK(is_int19(imm19));
1032 return truncate_to_int19(imm19) << ImmCmpBranch_offset;
1036 Instr Assembler::ImmTestBranch(int imm14) {
1037 CHECK(is_int14(imm14));
1038 return truncate_to_int14(imm14) << ImmTestBranch_offset;
1042 Instr Assembler::ImmTestBranchBit(unsigned bit_pos) {
1043 DCHECK(is_uint6(bit_pos));
1044 // Subtract five from the shift offset, as we need bit 5 from bit_pos.
1045 unsigned b5 = bit_pos << (ImmTestBranchBit5_offset - 5);
1046 unsigned b40 = bit_pos << ImmTestBranchBit40_offset;
1047 b5 &= ImmTestBranchBit5_mask;
1048 b40 &= ImmTestBranchBit40_mask;
1053 Instr Assembler::SF(Register rd) {
1054 return rd.Is64Bits() ? SixtyFourBits : ThirtyTwoBits;
1058 Instr Assembler::ImmAddSub(int64_t imm) {
1059 DCHECK(IsImmAddSub(imm));
1060 if (is_uint12(imm)) { // No shift required.
1061 return imm << ImmAddSub_offset;
1063 return ((imm >> 12) << ImmAddSub_offset) | (1 << ShiftAddSub_offset);
1068 Instr Assembler::ImmS(unsigned imms, unsigned reg_size) {
1069 DCHECK(((reg_size == kXRegSizeInBits) && is_uint6(imms)) ||
1070 ((reg_size == kWRegSizeInBits) && is_uint5(imms)));
1072 return imms << ImmS_offset;
1076 Instr Assembler::ImmR(unsigned immr, unsigned reg_size) {
1077 DCHECK(((reg_size == kXRegSizeInBits) && is_uint6(immr)) ||
1078 ((reg_size == kWRegSizeInBits) && is_uint5(immr)));
1080 DCHECK(is_uint6(immr));
1081 return immr << ImmR_offset;
1085 Instr Assembler::ImmSetBits(unsigned imms, unsigned reg_size) {
1086 DCHECK((reg_size == kWRegSizeInBits) || (reg_size == kXRegSizeInBits));
1087 DCHECK(is_uint6(imms));
1088 DCHECK((reg_size == kXRegSizeInBits) || is_uint6(imms + 3));
1090 return imms << ImmSetBits_offset;
1094 Instr Assembler::ImmRotate(unsigned immr, unsigned reg_size) {
1095 DCHECK((reg_size == kWRegSizeInBits) || (reg_size == kXRegSizeInBits));
1096 DCHECK(((reg_size == kXRegSizeInBits) && is_uint6(immr)) ||
1097 ((reg_size == kWRegSizeInBits) && is_uint5(immr)));
1099 return immr << ImmRotate_offset;
1103 Instr Assembler::ImmLLiteral(int imm19) {
1104 CHECK(is_int19(imm19));
1105 return truncate_to_int19(imm19) << ImmLLiteral_offset;
1109 Instr Assembler::BitN(unsigned bitn, unsigned reg_size) {
1110 DCHECK((reg_size == kWRegSizeInBits) || (reg_size == kXRegSizeInBits));
1111 DCHECK((reg_size == kXRegSizeInBits) || (bitn == 0));
1113 return bitn << BitN_offset;
1117 Instr Assembler::ShiftDP(Shift shift) {
1118 DCHECK(shift == LSL || shift == LSR || shift == ASR || shift == ROR);
1119 return shift << ShiftDP_offset;
1123 Instr Assembler::ImmDPShift(unsigned amount) {
1124 DCHECK(is_uint6(amount));
1125 return amount << ImmDPShift_offset;
1129 Instr Assembler::ExtendMode(Extend extend) {
1130 return extend << ExtendMode_offset;
1134 Instr Assembler::ImmExtendShift(unsigned left_shift) {
1135 DCHECK(left_shift <= 4);
1136 return left_shift << ImmExtendShift_offset;
1140 Instr Assembler::ImmCondCmp(unsigned imm) {
1141 DCHECK(is_uint5(imm));
1142 return imm << ImmCondCmp_offset;
1146 Instr Assembler::Nzcv(StatusFlags nzcv) {
1147 return ((nzcv >> Flags_offset) & 0xf) << Nzcv_offset;
1151 Instr Assembler::ImmLSUnsigned(int imm12) {
1152 DCHECK(is_uint12(imm12));
1153 return imm12 << ImmLSUnsigned_offset;
1157 Instr Assembler::ImmLS(int imm9) {
1158 DCHECK(is_int9(imm9));
1159 return truncate_to_int9(imm9) << ImmLS_offset;
1163 Instr Assembler::ImmLSPair(int imm7, LSDataSize size) {
1164 DCHECK(((imm7 >> size) << size) == imm7);
1165 int scaled_imm7 = imm7 >> size;
1166 DCHECK(is_int7(scaled_imm7));
1167 return truncate_to_int7(scaled_imm7) << ImmLSPair_offset;
1171 Instr Assembler::ImmShiftLS(unsigned shift_amount) {
1172 DCHECK(is_uint1(shift_amount));
1173 return shift_amount << ImmShiftLS_offset;
1177 Instr Assembler::ImmException(int imm16) {
1178 DCHECK(is_uint16(imm16));
1179 return imm16 << ImmException_offset;
1183 Instr Assembler::ImmSystemRegister(int imm15) {
1184 DCHECK(is_uint15(imm15));
1185 return imm15 << ImmSystemRegister_offset;
1189 Instr Assembler::ImmHint(int imm7) {
1190 DCHECK(is_uint7(imm7));
1191 return imm7 << ImmHint_offset;
1195 Instr Assembler::ImmBarrierDomain(int imm2) {
1196 DCHECK(is_uint2(imm2));
1197 return imm2 << ImmBarrierDomain_offset;
1201 Instr Assembler::ImmBarrierType(int imm2) {
1202 DCHECK(is_uint2(imm2));
1203 return imm2 << ImmBarrierType_offset;
1207 LSDataSize Assembler::CalcLSDataSize(LoadStoreOp op) {
1208 DCHECK((SizeLS_offset + SizeLS_width) == (kInstructionSize * 8));
1209 return static_cast<LSDataSize>(op >> SizeLS_offset);
1213 Instr Assembler::ImmMoveWide(uint64_t imm) {
1214 DCHECK(is_uint16(imm));
1215 return imm << ImmMoveWide_offset;
1219 Instr Assembler::ShiftMoveWide(int64_t shift) {
1220 DCHECK(is_uint2(shift));
1221 return shift << ShiftMoveWide_offset;
1225 Instr Assembler::FPType(FPRegister fd) {
1226 return fd.Is64Bits() ? FP64 : FP32;
1230 Instr Assembler::FPScale(unsigned scale) {
1231 DCHECK(is_uint6(scale));
1232 return scale << FPScale_offset;
1236 const Register& Assembler::AppropriateZeroRegFor(const CPURegister& reg) const {
1237 return reg.Is64Bits() ? xzr : wzr;
1241 inline void Assembler::CheckBufferSpace() {
1242 DCHECK(pc_ < (buffer_ + buffer_size_));
1243 if (buffer_space() < kGap) {
1249 inline void Assembler::CheckBuffer() {
1251 if (pc_offset() >= next_veneer_pool_check_) {
1252 CheckVeneerPool(false, true);
1254 if (pc_offset() >= next_constant_pool_check_) {
1255 CheckConstPool(false, true);
1260 TypeFeedbackId Assembler::RecordedAstId() {
1261 DCHECK(!recorded_ast_id_.IsNone());
1262 return recorded_ast_id_;
1266 void Assembler::ClearRecordedAstId() {
1267 recorded_ast_id_ = TypeFeedbackId::None();
1271 } } // namespace v8::internal
1273 #endif // V8_ARM64_ASSEMBLER_ARM64_INL_H_