Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / v8 / src / arm64 / assembler-arm64-inl.h
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.
4
5 #ifndef V8_ARM64_ASSEMBLER_ARM64_INL_H_
6 #define V8_ARM64_ASSEMBLER_ARM64_INL_H_
7
8 #include "arm64/assembler-arm64.h"
9 #include "cpu.h"
10 #include "debug.h"
11
12
13 namespace v8 {
14 namespace internal {
15
16
17 void RelocInfo::apply(intptr_t delta) {
18   UNIMPLEMENTED();
19 }
20
21
22 void RelocInfo::set_target_address(Address target, WriteBarrierMode mode) {
23   ASSERT(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_));
24   Assembler::set_target_address_at(pc_, host_, target);
25   if (mode == UPDATE_WRITE_BARRIER && host() != NULL && IsCodeTarget(rmode_)) {
26     Object* target_code = Code::GetCodeFromTargetAddress(target);
27     host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(
28         host(), this, HeapObject::cast(target_code));
29   }
30 }
31
32
33 inline unsigned CPURegister::code() const {
34   ASSERT(IsValid());
35   return reg_code;
36 }
37
38
39 inline CPURegister::RegisterType CPURegister::type() const {
40   ASSERT(IsValidOrNone());
41   return reg_type;
42 }
43
44
45 inline RegList CPURegister::Bit() const {
46   ASSERT(reg_code < (sizeof(RegList) * kBitsPerByte));
47   return IsValid() ? 1UL << reg_code : 0;
48 }
49
50
51 inline unsigned CPURegister::SizeInBits() const {
52   ASSERT(IsValid());
53   return reg_size;
54 }
55
56
57 inline int CPURegister::SizeInBytes() const {
58   ASSERT(IsValid());
59   ASSERT(SizeInBits() % 8 == 0);
60   return reg_size / 8;
61 }
62
63
64 inline bool CPURegister::Is32Bits() const {
65   ASSERT(IsValid());
66   return reg_size == 32;
67 }
68
69
70 inline bool CPURegister::Is64Bits() const {
71   ASSERT(IsValid());
72   return reg_size == 64;
73 }
74
75
76 inline bool CPURegister::IsValid() const {
77   if (IsValidRegister() || IsValidFPRegister()) {
78     ASSERT(!IsNone());
79     return true;
80   } else {
81     ASSERT(IsNone());
82     return false;
83   }
84 }
85
86
87 inline bool CPURegister::IsValidRegister() const {
88   return IsRegister() &&
89          ((reg_size == kWRegSizeInBits) || (reg_size == kXRegSizeInBits)) &&
90          ((reg_code < kNumberOfRegisters) || (reg_code == kSPRegInternalCode));
91 }
92
93
94 inline bool CPURegister::IsValidFPRegister() const {
95   return IsFPRegister() &&
96          ((reg_size == kSRegSizeInBits) || (reg_size == kDRegSizeInBits)) &&
97          (reg_code < kNumberOfFPRegisters);
98 }
99
100
101 inline bool CPURegister::IsNone() const {
102   // kNoRegister types should always have size 0 and code 0.
103   ASSERT((reg_type != kNoRegister) || (reg_code == 0));
104   ASSERT((reg_type != kNoRegister) || (reg_size == 0));
105
106   return reg_type == kNoRegister;
107 }
108
109
110 inline bool CPURegister::Is(const CPURegister& other) const {
111   ASSERT(IsValidOrNone() && other.IsValidOrNone());
112   return (reg_code == other.reg_code) && (reg_size == other.reg_size) &&
113          (reg_type == other.reg_type);
114 }
115
116
117 inline bool CPURegister::IsRegister() const {
118   return reg_type == kRegister;
119 }
120
121
122 inline bool CPURegister::IsFPRegister() const {
123   return reg_type == kFPRegister;
124 }
125
126
127 inline bool CPURegister::IsSameSizeAndType(const CPURegister& other) const {
128   return (reg_size == other.reg_size) && (reg_type == other.reg_type);
129 }
130
131
132 inline bool CPURegister::IsValidOrNone() const {
133   return IsValid() || IsNone();
134 }
135
136
137 inline bool CPURegister::IsZero() const {
138   ASSERT(IsValid());
139   return IsRegister() && (reg_code == kZeroRegCode);
140 }
141
142
143 inline bool CPURegister::IsSP() const {
144   ASSERT(IsValid());
145   return IsRegister() && (reg_code == kSPRegInternalCode);
146 }
147
148
149 inline void CPURegList::Combine(const CPURegList& other) {
150   ASSERT(IsValid());
151   ASSERT(other.type() == type_);
152   ASSERT(other.RegisterSizeInBits() == size_);
153   list_ |= other.list();
154 }
155
156
157 inline void CPURegList::Remove(const CPURegList& other) {
158   ASSERT(IsValid());
159   if (other.type() == type_) {
160     list_ &= ~other.list();
161   }
162 }
163
164
165 inline void CPURegList::Combine(const CPURegister& other) {
166   ASSERT(other.type() == type_);
167   ASSERT(other.SizeInBits() == size_);
168   Combine(other.code());
169 }
170
171
172 inline void CPURegList::Remove(const CPURegister& other1,
173                                const CPURegister& other2,
174                                const CPURegister& other3,
175                                const CPURegister& other4) {
176   if (!other1.IsNone() && (other1.type() == type_)) Remove(other1.code());
177   if (!other2.IsNone() && (other2.type() == type_)) Remove(other2.code());
178   if (!other3.IsNone() && (other3.type() == type_)) Remove(other3.code());
179   if (!other4.IsNone() && (other4.type() == type_)) Remove(other4.code());
180 }
181
182
183 inline void CPURegList::Combine(int code) {
184   ASSERT(IsValid());
185   ASSERT(CPURegister::Create(code, size_, type_).IsValid());
186   list_ |= (1UL << code);
187 }
188
189
190 inline void CPURegList::Remove(int code) {
191   ASSERT(IsValid());
192   ASSERT(CPURegister::Create(code, size_, type_).IsValid());
193   list_ &= ~(1UL << code);
194 }
195
196
197 inline Register Register::XRegFromCode(unsigned code) {
198   // This function returns the zero register when code = 31. The stack pointer
199   // can not be returned.
200   ASSERT(code < kNumberOfRegisters);
201   return Register::Create(code, kXRegSizeInBits);
202 }
203
204
205 inline Register Register::WRegFromCode(unsigned code) {
206   ASSERT(code < kNumberOfRegisters);
207   return Register::Create(code, kWRegSizeInBits);
208 }
209
210
211 inline FPRegister FPRegister::SRegFromCode(unsigned code) {
212   ASSERT(code < kNumberOfFPRegisters);
213   return FPRegister::Create(code, kSRegSizeInBits);
214 }
215
216
217 inline FPRegister FPRegister::DRegFromCode(unsigned code) {
218   ASSERT(code < kNumberOfFPRegisters);
219   return FPRegister::Create(code, kDRegSizeInBits);
220 }
221
222
223 inline Register CPURegister::W() const {
224   ASSERT(IsValidRegister());
225   return Register::WRegFromCode(reg_code);
226 }
227
228
229 inline Register CPURegister::X() const {
230   ASSERT(IsValidRegister());
231   return Register::XRegFromCode(reg_code);
232 }
233
234
235 inline FPRegister CPURegister::S() const {
236   ASSERT(IsValidFPRegister());
237   return FPRegister::SRegFromCode(reg_code);
238 }
239
240
241 inline FPRegister CPURegister::D() const {
242   ASSERT(IsValidFPRegister());
243   return FPRegister::DRegFromCode(reg_code);
244 }
245
246
247 // Operand.
248 template<typename T>
249 Operand::Operand(Handle<T> value) : reg_(NoReg) {
250   initialize_handle(value);
251 }
252
253
254 // Default initializer is for int types
255 template<typename int_t>
256 struct OperandInitializer {
257   static const bool kIsIntType = true;
258   static inline RelocInfo::Mode rmode_for(int_t) {
259     return sizeof(int_t) == 8 ? RelocInfo::NONE64 : RelocInfo::NONE32;
260   }
261   static inline int64_t immediate_for(int_t t) {
262     STATIC_ASSERT(sizeof(int_t) <= 8);
263     return t;
264   }
265 };
266
267
268 template<>
269 struct OperandInitializer<Smi*> {
270   static const bool kIsIntType = false;
271   static inline RelocInfo::Mode rmode_for(Smi* t) {
272     return RelocInfo::NONE64;
273   }
274   static inline int64_t immediate_for(Smi* t) {;
275     return reinterpret_cast<int64_t>(t);
276   }
277 };
278
279
280 template<>
281 struct OperandInitializer<ExternalReference> {
282   static const bool kIsIntType = false;
283   static inline RelocInfo::Mode rmode_for(ExternalReference t) {
284     return RelocInfo::EXTERNAL_REFERENCE;
285   }
286   static inline int64_t immediate_for(ExternalReference t) {;
287     return reinterpret_cast<int64_t>(t.address());
288   }
289 };
290
291
292 template<typename T>
293 Operand::Operand(T t)
294     : immediate_(OperandInitializer<T>::immediate_for(t)),
295       reg_(NoReg),
296       rmode_(OperandInitializer<T>::rmode_for(t)) {}
297
298
299 template<typename T>
300 Operand::Operand(T t, RelocInfo::Mode rmode)
301     : immediate_(OperandInitializer<T>::immediate_for(t)),
302       reg_(NoReg),
303       rmode_(rmode) {
304   STATIC_ASSERT(OperandInitializer<T>::kIsIntType);
305 }
306
307
308 Operand::Operand(Register reg, Shift shift, unsigned shift_amount)
309     : reg_(reg),
310       shift_(shift),
311       extend_(NO_EXTEND),
312       shift_amount_(shift_amount),
313       rmode_(reg.Is64Bits() ? RelocInfo::NONE64 : RelocInfo::NONE32) {
314   ASSERT(reg.Is64Bits() || (shift_amount < kWRegSizeInBits));
315   ASSERT(reg.Is32Bits() || (shift_amount < kXRegSizeInBits));
316   ASSERT(!reg.IsSP());
317 }
318
319
320 Operand::Operand(Register reg, Extend extend, unsigned shift_amount)
321     : reg_(reg),
322       shift_(NO_SHIFT),
323       extend_(extend),
324       shift_amount_(shift_amount),
325       rmode_(reg.Is64Bits() ? RelocInfo::NONE64 : RelocInfo::NONE32) {
326   ASSERT(reg.IsValid());
327   ASSERT(shift_amount <= 4);
328   ASSERT(!reg.IsSP());
329
330   // Extend modes SXTX and UXTX require a 64-bit register.
331   ASSERT(reg.Is64Bits() || ((extend != SXTX) && (extend != UXTX)));
332 }
333
334
335 bool Operand::IsImmediate() const {
336   return reg_.Is(NoReg);
337 }
338
339
340 bool Operand::IsShiftedRegister() const {
341   return reg_.IsValid() && (shift_ != NO_SHIFT);
342 }
343
344
345 bool Operand::IsExtendedRegister() const {
346   return reg_.IsValid() && (extend_ != NO_EXTEND);
347 }
348
349
350 bool Operand::IsZero() const {
351   if (IsImmediate()) {
352     return immediate() == 0;
353   } else {
354     return reg().IsZero();
355   }
356 }
357
358
359 Operand Operand::ToExtendedRegister() const {
360   ASSERT(IsShiftedRegister());
361   ASSERT((shift_ == LSL) && (shift_amount_ <= 4));
362   return Operand(reg_, reg_.Is64Bits() ? UXTX : UXTW, shift_amount_);
363 }
364
365
366 int64_t Operand::immediate() const {
367   ASSERT(IsImmediate());
368   return immediate_;
369 }
370
371
372 Register Operand::reg() const {
373   ASSERT(IsShiftedRegister() || IsExtendedRegister());
374   return reg_;
375 }
376
377
378 Shift Operand::shift() const {
379   ASSERT(IsShiftedRegister());
380   return shift_;
381 }
382
383
384 Extend Operand::extend() const {
385   ASSERT(IsExtendedRegister());
386   return extend_;
387 }
388
389
390 unsigned Operand::shift_amount() const {
391   ASSERT(IsShiftedRegister() || IsExtendedRegister());
392   return shift_amount_;
393 }
394
395
396 Operand Operand::UntagSmi(Register smi) {
397   ASSERT(smi.Is64Bits());
398   return Operand(smi, ASR, kSmiShift);
399 }
400
401
402 Operand Operand::UntagSmiAndScale(Register smi, int scale) {
403   ASSERT(smi.Is64Bits());
404   ASSERT((scale >= 0) && (scale <= (64 - kSmiValueSize)));
405   if (scale > kSmiShift) {
406     return Operand(smi, LSL, scale - kSmiShift);
407   } else if (scale < kSmiShift) {
408     return Operand(smi, ASR, kSmiShift - scale);
409   }
410   return Operand(smi);
411 }
412
413
414 MemOperand::MemOperand(Register base, ptrdiff_t offset, AddrMode addrmode)
415   : base_(base), regoffset_(NoReg), offset_(offset), addrmode_(addrmode),
416     shift_(NO_SHIFT), extend_(NO_EXTEND), shift_amount_(0) {
417   ASSERT(base.Is64Bits() && !base.IsZero());
418 }
419
420
421 MemOperand::MemOperand(Register base,
422                        Register regoffset,
423                        Extend extend,
424                        unsigned shift_amount)
425   : base_(base), regoffset_(regoffset), offset_(0), addrmode_(Offset),
426     shift_(NO_SHIFT), extend_(extend), shift_amount_(shift_amount) {
427   ASSERT(base.Is64Bits() && !base.IsZero());
428   ASSERT(!regoffset.IsSP());
429   ASSERT((extend == UXTW) || (extend == SXTW) || (extend == SXTX));
430
431   // SXTX extend mode requires a 64-bit offset register.
432   ASSERT(regoffset.Is64Bits() || (extend != SXTX));
433 }
434
435
436 MemOperand::MemOperand(Register base,
437                        Register regoffset,
438                        Shift shift,
439                        unsigned shift_amount)
440   : base_(base), regoffset_(regoffset), offset_(0), addrmode_(Offset),
441     shift_(shift), extend_(NO_EXTEND), shift_amount_(shift_amount) {
442   ASSERT(base.Is64Bits() && !base.IsZero());
443   ASSERT(regoffset.Is64Bits() && !regoffset.IsSP());
444   ASSERT(shift == LSL);
445 }
446
447
448 MemOperand::MemOperand(Register base, const Operand& offset, AddrMode addrmode)
449   : base_(base), addrmode_(addrmode) {
450   ASSERT(base.Is64Bits() && !base.IsZero());
451
452   if (offset.IsImmediate()) {
453     offset_ = offset.immediate();
454
455     regoffset_ = NoReg;
456   } else if (offset.IsShiftedRegister()) {
457     ASSERT(addrmode == Offset);
458
459     regoffset_ = offset.reg();
460     shift_= offset.shift();
461     shift_amount_ = offset.shift_amount();
462
463     extend_ = NO_EXTEND;
464     offset_ = 0;
465
466     // These assertions match those in the shifted-register constructor.
467     ASSERT(regoffset_.Is64Bits() && !regoffset_.IsSP());
468     ASSERT(shift_ == LSL);
469   } else {
470     ASSERT(offset.IsExtendedRegister());
471     ASSERT(addrmode == Offset);
472
473     regoffset_ = offset.reg();
474     extend_ = offset.extend();
475     shift_amount_ = offset.shift_amount();
476
477     shift_= NO_SHIFT;
478     offset_ = 0;
479
480     // These assertions match those in the extended-register constructor.
481     ASSERT(!regoffset_.IsSP());
482     ASSERT((extend_ == UXTW) || (extend_ == SXTW) || (extend_ == SXTX));
483     ASSERT((regoffset_.Is64Bits() || (extend_ != SXTX)));
484   }
485 }
486
487 bool MemOperand::IsImmediateOffset() const {
488   return (addrmode_ == Offset) && regoffset_.Is(NoReg);
489 }
490
491
492 bool MemOperand::IsRegisterOffset() const {
493   return (addrmode_ == Offset) && !regoffset_.Is(NoReg);
494 }
495
496
497 bool MemOperand::IsPreIndex() const {
498   return addrmode_ == PreIndex;
499 }
500
501
502 bool MemOperand::IsPostIndex() const {
503   return addrmode_ == PostIndex;
504 }
505
506 Operand MemOperand::OffsetAsOperand() const {
507   if (IsImmediateOffset()) {
508     return offset();
509   } else {
510     ASSERT(IsRegisterOffset());
511     if (extend() == NO_EXTEND) {
512       return Operand(regoffset(), shift(), shift_amount());
513     } else {
514       return Operand(regoffset(), extend(), shift_amount());
515     }
516   }
517 }
518
519
520 void Assembler::Unreachable() {
521 #ifdef USE_SIMULATOR
522   debug("UNREACHABLE", __LINE__, BREAK);
523 #else
524   // Crash by branching to 0. lr now points near the fault.
525   Emit(BLR | Rn(xzr));
526 #endif
527 }
528
529
530 Address Assembler::target_pointer_address_at(Address pc) {
531   Instruction* instr = reinterpret_cast<Instruction*>(pc);
532   ASSERT(instr->IsLdrLiteralX());
533   return reinterpret_cast<Address>(instr->ImmPCOffsetTarget());
534 }
535
536
537 // Read/Modify the code target address in the branch/call instruction at pc.
538 Address Assembler::target_address_at(Address pc,
539                                      ConstantPoolArray* constant_pool) {
540   return Memory::Address_at(target_pointer_address_at(pc));
541 }
542
543
544 Address Assembler::target_address_at(Address pc, Code* code) {
545   ConstantPoolArray* constant_pool = code ? code->constant_pool() : NULL;
546   return target_address_at(pc, constant_pool);
547 }
548
549
550 Address Assembler::target_address_from_return_address(Address pc) {
551   // Returns the address of the call target from the return address that will
552   // be returned to after a call.
553   // Call sequence on ARM64 is:
554   //  ldr ip0, #... @ load from literal pool
555   //  blr ip0
556   Address candidate = pc - 2 * kInstructionSize;
557   Instruction* instr = reinterpret_cast<Instruction*>(candidate);
558   USE(instr);
559   ASSERT(instr->IsLdrLiteralX());
560   return candidate;
561 }
562
563
564 Address Assembler::return_address_from_call_start(Address pc) {
565   // The call, generated by MacroAssembler::Call, is one of two possible
566   // sequences:
567   //
568   // Without relocation:
569   //  movz  temp, #(target & 0x000000000000ffff)
570   //  movk  temp, #(target & 0x00000000ffff0000)
571   //  movk  temp, #(target & 0x0000ffff00000000)
572   //  blr   temp
573   //
574   // With relocation:
575   //  ldr   temp, =target
576   //  blr   temp
577   //
578   // The return address is immediately after the blr instruction in both cases,
579   // so it can be found by adding the call size to the address at the start of
580   // the call sequence.
581   STATIC_ASSERT(Assembler::kCallSizeWithoutRelocation == 4 * kInstructionSize);
582   STATIC_ASSERT(Assembler::kCallSizeWithRelocation == 2 * kInstructionSize);
583
584   Instruction* instr = reinterpret_cast<Instruction*>(pc);
585   if (instr->IsMovz()) {
586     // Verify the instruction sequence.
587     ASSERT(instr->following(1)->IsMovk());
588     ASSERT(instr->following(2)->IsMovk());
589     ASSERT(instr->following(3)->IsBranchAndLinkToRegister());
590     return pc + Assembler::kCallSizeWithoutRelocation;
591   } else {
592     // Verify the instruction sequence.
593     ASSERT(instr->IsLdrLiteralX());
594     ASSERT(instr->following(1)->IsBranchAndLinkToRegister());
595     return pc + Assembler::kCallSizeWithRelocation;
596   }
597 }
598
599
600 void Assembler::deserialization_set_special_target_at(
601     Address constant_pool_entry, Code* code, Address target) {
602   Memory::Address_at(constant_pool_entry) = target;
603 }
604
605
606 void Assembler::set_target_address_at(Address pc,
607                                       ConstantPoolArray* constant_pool,
608                                       Address target) {
609   Memory::Address_at(target_pointer_address_at(pc)) = target;
610   // Intuitively, we would think it is necessary to always flush the
611   // instruction cache after patching a target address in the code as follows:
612   //   CPU::FlushICache(pc, sizeof(target));
613   // However, on ARM, an instruction is actually patched in the case of
614   // embedded constants of the form:
615   // ldr   ip, [pc, #...]
616   // since the instruction accessing this address in the constant pool remains
617   // unchanged, a flush is not required.
618 }
619
620
621 void Assembler::set_target_address_at(Address pc,
622                                       Code* code,
623                                       Address target) {
624   ConstantPoolArray* constant_pool = code ? code->constant_pool() : NULL;
625   set_target_address_at(pc, constant_pool, target);
626 }
627
628
629 int RelocInfo::target_address_size() {
630   return kPointerSize;
631 }
632
633
634 Address RelocInfo::target_address() {
635   ASSERT(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_));
636   return Assembler::target_address_at(pc_, host_);
637 }
638
639
640 Address RelocInfo::target_address_address() {
641   ASSERT(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_)
642                               || rmode_ == EMBEDDED_OBJECT
643                               || rmode_ == EXTERNAL_REFERENCE);
644   return Assembler::target_pointer_address_at(pc_);
645 }
646
647
648 Address RelocInfo::constant_pool_entry_address() {
649   ASSERT(IsInConstantPool());
650   return Assembler::target_pointer_address_at(pc_);
651 }
652
653
654 Object* RelocInfo::target_object() {
655   ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
656   return reinterpret_cast<Object*>(Assembler::target_address_at(pc_, host_));
657 }
658
659
660 Handle<Object> RelocInfo::target_object_handle(Assembler* origin) {
661   ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
662   return Handle<Object>(reinterpret_cast<Object**>(
663       Assembler::target_address_at(pc_, host_)));
664 }
665
666
667 void RelocInfo::set_target_object(Object* target, WriteBarrierMode mode) {
668   ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
669   ASSERT(!target->IsConsString());
670   Assembler::set_target_address_at(pc_, host_,
671                                    reinterpret_cast<Address>(target));
672   if (mode == UPDATE_WRITE_BARRIER &&
673       host() != NULL &&
674       target->IsHeapObject()) {
675     host()->GetHeap()->incremental_marking()->RecordWrite(
676         host(), &Memory::Object_at(pc_), HeapObject::cast(target));
677   }
678 }
679
680
681 Address RelocInfo::target_reference() {
682   ASSERT(rmode_ == EXTERNAL_REFERENCE);
683   return Assembler::target_address_at(pc_, host_);
684 }
685
686
687 Address RelocInfo::target_runtime_entry(Assembler* origin) {
688   ASSERT(IsRuntimeEntry(rmode_));
689   return target_address();
690 }
691
692
693 void RelocInfo::set_target_runtime_entry(Address target,
694                                          WriteBarrierMode mode) {
695   ASSERT(IsRuntimeEntry(rmode_));
696   if (target_address() != target) set_target_address(target, mode);
697 }
698
699
700 Handle<Cell> RelocInfo::target_cell_handle() {
701   UNIMPLEMENTED();
702   Cell *null_cell = NULL;
703   return Handle<Cell>(null_cell);
704 }
705
706
707 Cell* RelocInfo::target_cell() {
708   ASSERT(rmode_ == RelocInfo::CELL);
709   return Cell::FromValueAddress(Memory::Address_at(pc_));
710 }
711
712
713 void RelocInfo::set_target_cell(Cell* cell, WriteBarrierMode mode) {
714   UNIMPLEMENTED();
715 }
716
717
718 static const int kCodeAgeSequenceSize = 5 * kInstructionSize;
719 static const int kCodeAgeStubEntryOffset = 3 * kInstructionSize;
720
721
722 Handle<Object> RelocInfo::code_age_stub_handle(Assembler* origin) {
723   UNREACHABLE();  // This should never be reached on ARM64.
724   return Handle<Object>();
725 }
726
727
728 Code* RelocInfo::code_age_stub() {
729   ASSERT(rmode_ == RelocInfo::CODE_AGE_SEQUENCE);
730   ASSERT(!Code::IsYoungSequence(pc_));
731   // Read the stub entry point from the code age sequence.
732   Address stub_entry_address = pc_ + kCodeAgeStubEntryOffset;
733   return Code::GetCodeFromTargetAddress(Memory::Address_at(stub_entry_address));
734 }
735
736
737 void RelocInfo::set_code_age_stub(Code* stub) {
738   ASSERT(rmode_ == RelocInfo::CODE_AGE_SEQUENCE);
739   ASSERT(!Code::IsYoungSequence(pc_));
740   // Overwrite the stub entry point in the code age sequence. This is loaded as
741   // a literal so there is no need to call FlushICache here.
742   Address stub_entry_address = pc_ + kCodeAgeStubEntryOffset;
743   Memory::Address_at(stub_entry_address) = stub->instruction_start();
744 }
745
746
747 Address RelocInfo::call_address() {
748   ASSERT((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
749          (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
750   // For the above sequences the Relocinfo points to the load literal loading
751   // the call address.
752   return Assembler::target_address_at(pc_, host_);
753 }
754
755
756 void RelocInfo::set_call_address(Address target) {
757   ASSERT((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
758          (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
759   Assembler::set_target_address_at(pc_, host_, target);
760   if (host() != NULL) {
761     Object* target_code = Code::GetCodeFromTargetAddress(target);
762     host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(
763         host(), this, HeapObject::cast(target_code));
764   }
765 }
766
767
768 void RelocInfo::WipeOut() {
769   ASSERT(IsEmbeddedObject(rmode_) ||
770          IsCodeTarget(rmode_) ||
771          IsRuntimeEntry(rmode_) ||
772          IsExternalReference(rmode_));
773   Assembler::set_target_address_at(pc_, host_, NULL);
774 }
775
776
777 bool RelocInfo::IsPatchedReturnSequence() {
778   // The sequence must be:
779   //   ldr ip0, [pc, #offset]
780   //   blr ip0
781   // See arm64/debug-arm64.cc BreakLocationIterator::SetDebugBreakAtReturn().
782   Instruction* i1 = reinterpret_cast<Instruction*>(pc_);
783   Instruction* i2 = i1->following();
784   return i1->IsLdrLiteralX() && (i1->Rt() == ip0.code()) &&
785          i2->IsBranchAndLinkToRegister() && (i2->Rn() == ip0.code());
786 }
787
788
789 bool RelocInfo::IsPatchedDebugBreakSlotSequence() {
790   Instruction* current_instr = reinterpret_cast<Instruction*>(pc_);
791   return !current_instr->IsNop(Assembler::DEBUG_BREAK_NOP);
792 }
793
794
795 void RelocInfo::Visit(Isolate* isolate, ObjectVisitor* visitor) {
796   RelocInfo::Mode mode = rmode();
797   if (mode == RelocInfo::EMBEDDED_OBJECT) {
798     visitor->VisitEmbeddedPointer(this);
799   } else if (RelocInfo::IsCodeTarget(mode)) {
800     visitor->VisitCodeTarget(this);
801   } else if (mode == RelocInfo::CELL) {
802     visitor->VisitCell(this);
803   } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
804     visitor->VisitExternalReference(this);
805   } else if (((RelocInfo::IsJSReturn(mode) &&
806               IsPatchedReturnSequence()) ||
807              (RelocInfo::IsDebugBreakSlot(mode) &&
808               IsPatchedDebugBreakSlotSequence())) &&
809              isolate->debug()->has_break_points()) {
810     visitor->VisitDebugTarget(this);
811   } else if (RelocInfo::IsRuntimeEntry(mode)) {
812     visitor->VisitRuntimeEntry(this);
813   }
814 }
815
816
817 template<typename StaticVisitor>
818 void RelocInfo::Visit(Heap* heap) {
819   RelocInfo::Mode mode = rmode();
820   if (mode == RelocInfo::EMBEDDED_OBJECT) {
821     StaticVisitor::VisitEmbeddedPointer(heap, this);
822   } else if (RelocInfo::IsCodeTarget(mode)) {
823     StaticVisitor::VisitCodeTarget(heap, this);
824   } else if (mode == RelocInfo::CELL) {
825     StaticVisitor::VisitCell(heap, this);
826   } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
827     StaticVisitor::VisitExternalReference(this);
828   } else if (heap->isolate()->debug()->has_break_points() &&
829              ((RelocInfo::IsJSReturn(mode) &&
830               IsPatchedReturnSequence()) ||
831              (RelocInfo::IsDebugBreakSlot(mode) &&
832               IsPatchedDebugBreakSlotSequence()))) {
833     StaticVisitor::VisitDebugTarget(heap, this);
834   } else if (RelocInfo::IsRuntimeEntry(mode)) {
835     StaticVisitor::VisitRuntimeEntry(this);
836   }
837 }
838
839
840 LoadStoreOp Assembler::LoadOpFor(const CPURegister& rt) {
841   ASSERT(rt.IsValid());
842   if (rt.IsRegister()) {
843     return rt.Is64Bits() ? LDR_x : LDR_w;
844   } else {
845     ASSERT(rt.IsFPRegister());
846     return rt.Is64Bits() ? LDR_d : LDR_s;
847   }
848 }
849
850
851 LoadStorePairOp Assembler::LoadPairOpFor(const CPURegister& rt,
852                                          const CPURegister& rt2) {
853   ASSERT(AreSameSizeAndType(rt, rt2));
854   USE(rt2);
855   if (rt.IsRegister()) {
856     return rt.Is64Bits() ? LDP_x : LDP_w;
857   } else {
858     ASSERT(rt.IsFPRegister());
859     return rt.Is64Bits() ? LDP_d : LDP_s;
860   }
861 }
862
863
864 LoadStoreOp Assembler::StoreOpFor(const CPURegister& rt) {
865   ASSERT(rt.IsValid());
866   if (rt.IsRegister()) {
867     return rt.Is64Bits() ? STR_x : STR_w;
868   } else {
869     ASSERT(rt.IsFPRegister());
870     return rt.Is64Bits() ? STR_d : STR_s;
871   }
872 }
873
874
875 LoadStorePairOp Assembler::StorePairOpFor(const CPURegister& rt,
876                                           const CPURegister& rt2) {
877   ASSERT(AreSameSizeAndType(rt, rt2));
878   USE(rt2);
879   if (rt.IsRegister()) {
880     return rt.Is64Bits() ? STP_x : STP_w;
881   } else {
882     ASSERT(rt.IsFPRegister());
883     return rt.Is64Bits() ? STP_d : STP_s;
884   }
885 }
886
887
888 LoadStorePairNonTemporalOp Assembler::LoadPairNonTemporalOpFor(
889     const CPURegister& rt, const CPURegister& rt2) {
890   ASSERT(AreSameSizeAndType(rt, rt2));
891   USE(rt2);
892   if (rt.IsRegister()) {
893     return rt.Is64Bits() ? LDNP_x : LDNP_w;
894   } else {
895     ASSERT(rt.IsFPRegister());
896     return rt.Is64Bits() ? LDNP_d : LDNP_s;
897   }
898 }
899
900
901 LoadStorePairNonTemporalOp Assembler::StorePairNonTemporalOpFor(
902     const CPURegister& rt, const CPURegister& rt2) {
903   ASSERT(AreSameSizeAndType(rt, rt2));
904   USE(rt2);
905   if (rt.IsRegister()) {
906     return rt.Is64Bits() ? STNP_x : STNP_w;
907   } else {
908     ASSERT(rt.IsFPRegister());
909     return rt.Is64Bits() ? STNP_d : STNP_s;
910   }
911 }
912
913
914 int Assembler::LinkAndGetInstructionOffsetTo(Label* label) {
915   ASSERT(kStartOfLabelLinkChain == 0);
916   int offset = LinkAndGetByteOffsetTo(label);
917   ASSERT(IsAligned(offset, kInstructionSize));
918   return offset >> kInstructionSizeLog2;
919 }
920
921
922 Instr Assembler::Flags(FlagsUpdate S) {
923   if (S == SetFlags) {
924     return 1 << FlagsUpdate_offset;
925   } else if (S == LeaveFlags) {
926     return 0 << FlagsUpdate_offset;
927   }
928   UNREACHABLE();
929   return 0;
930 }
931
932
933 Instr Assembler::Cond(Condition cond) {
934   return cond << Condition_offset;
935 }
936
937
938 Instr Assembler::ImmPCRelAddress(int imm21) {
939   CHECK(is_int21(imm21));
940   Instr imm = static_cast<Instr>(truncate_to_int21(imm21));
941   Instr immhi = (imm >> ImmPCRelLo_width) << ImmPCRelHi_offset;
942   Instr immlo = imm << ImmPCRelLo_offset;
943   return (immhi & ImmPCRelHi_mask) | (immlo & ImmPCRelLo_mask);
944 }
945
946
947 Instr Assembler::ImmUncondBranch(int imm26) {
948   CHECK(is_int26(imm26));
949   return truncate_to_int26(imm26) << ImmUncondBranch_offset;
950 }
951
952
953 Instr Assembler::ImmCondBranch(int imm19) {
954   CHECK(is_int19(imm19));
955   return truncate_to_int19(imm19) << ImmCondBranch_offset;
956 }
957
958
959 Instr Assembler::ImmCmpBranch(int imm19) {
960   CHECK(is_int19(imm19));
961   return truncate_to_int19(imm19) << ImmCmpBranch_offset;
962 }
963
964
965 Instr Assembler::ImmTestBranch(int imm14) {
966   CHECK(is_int14(imm14));
967   return truncate_to_int14(imm14) << ImmTestBranch_offset;
968 }
969
970
971 Instr Assembler::ImmTestBranchBit(unsigned bit_pos) {
972   ASSERT(is_uint6(bit_pos));
973   // Subtract five from the shift offset, as we need bit 5 from bit_pos.
974   unsigned b5 = bit_pos << (ImmTestBranchBit5_offset - 5);
975   unsigned b40 = bit_pos << ImmTestBranchBit40_offset;
976   b5 &= ImmTestBranchBit5_mask;
977   b40 &= ImmTestBranchBit40_mask;
978   return b5 | b40;
979 }
980
981
982 Instr Assembler::SF(Register rd) {
983     return rd.Is64Bits() ? SixtyFourBits : ThirtyTwoBits;
984 }
985
986
987 Instr Assembler::ImmAddSub(int64_t imm) {
988   ASSERT(IsImmAddSub(imm));
989   if (is_uint12(imm)) {  // No shift required.
990     return imm << ImmAddSub_offset;
991   } else {
992     return ((imm >> 12) << ImmAddSub_offset) | (1 << ShiftAddSub_offset);
993   }
994 }
995
996
997 Instr Assembler::ImmS(unsigned imms, unsigned reg_size) {
998   ASSERT(((reg_size == kXRegSizeInBits) && is_uint6(imms)) ||
999          ((reg_size == kWRegSizeInBits) && is_uint5(imms)));
1000   USE(reg_size);
1001   return imms << ImmS_offset;
1002 }
1003
1004
1005 Instr Assembler::ImmR(unsigned immr, unsigned reg_size) {
1006   ASSERT(((reg_size == kXRegSizeInBits) && is_uint6(immr)) ||
1007          ((reg_size == kWRegSizeInBits) && is_uint5(immr)));
1008   USE(reg_size);
1009   ASSERT(is_uint6(immr));
1010   return immr << ImmR_offset;
1011 }
1012
1013
1014 Instr Assembler::ImmSetBits(unsigned imms, unsigned reg_size) {
1015   ASSERT((reg_size == kWRegSizeInBits) || (reg_size == kXRegSizeInBits));
1016   ASSERT(is_uint6(imms));
1017   ASSERT((reg_size == kXRegSizeInBits) || is_uint6(imms + 3));
1018   USE(reg_size);
1019   return imms << ImmSetBits_offset;
1020 }
1021
1022
1023 Instr Assembler::ImmRotate(unsigned immr, unsigned reg_size) {
1024   ASSERT((reg_size == kWRegSizeInBits) || (reg_size == kXRegSizeInBits));
1025   ASSERT(((reg_size == kXRegSizeInBits) && is_uint6(immr)) ||
1026          ((reg_size == kWRegSizeInBits) && is_uint5(immr)));
1027   USE(reg_size);
1028   return immr << ImmRotate_offset;
1029 }
1030
1031
1032 Instr Assembler::ImmLLiteral(int imm19) {
1033   CHECK(is_int19(imm19));
1034   return truncate_to_int19(imm19) << ImmLLiteral_offset;
1035 }
1036
1037
1038 Instr Assembler::BitN(unsigned bitn, unsigned reg_size) {
1039   ASSERT((reg_size == kWRegSizeInBits) || (reg_size == kXRegSizeInBits));
1040   ASSERT((reg_size == kXRegSizeInBits) || (bitn == 0));
1041   USE(reg_size);
1042   return bitn << BitN_offset;
1043 }
1044
1045
1046 Instr Assembler::ShiftDP(Shift shift) {
1047   ASSERT(shift == LSL || shift == LSR || shift == ASR || shift == ROR);
1048   return shift << ShiftDP_offset;
1049 }
1050
1051
1052 Instr Assembler::ImmDPShift(unsigned amount) {
1053   ASSERT(is_uint6(amount));
1054   return amount << ImmDPShift_offset;
1055 }
1056
1057
1058 Instr Assembler::ExtendMode(Extend extend) {
1059   return extend << ExtendMode_offset;
1060 }
1061
1062
1063 Instr Assembler::ImmExtendShift(unsigned left_shift) {
1064   ASSERT(left_shift <= 4);
1065   return left_shift << ImmExtendShift_offset;
1066 }
1067
1068
1069 Instr Assembler::ImmCondCmp(unsigned imm) {
1070   ASSERT(is_uint5(imm));
1071   return imm << ImmCondCmp_offset;
1072 }
1073
1074
1075 Instr Assembler::Nzcv(StatusFlags nzcv) {
1076   return ((nzcv >> Flags_offset) & 0xf) << Nzcv_offset;
1077 }
1078
1079
1080 Instr Assembler::ImmLSUnsigned(int imm12) {
1081   ASSERT(is_uint12(imm12));
1082   return imm12 << ImmLSUnsigned_offset;
1083 }
1084
1085
1086 Instr Assembler::ImmLS(int imm9) {
1087   ASSERT(is_int9(imm9));
1088   return truncate_to_int9(imm9) << ImmLS_offset;
1089 }
1090
1091
1092 Instr Assembler::ImmLSPair(int imm7, LSDataSize size) {
1093   ASSERT(((imm7 >> size) << size) == imm7);
1094   int scaled_imm7 = imm7 >> size;
1095   ASSERT(is_int7(scaled_imm7));
1096   return truncate_to_int7(scaled_imm7) << ImmLSPair_offset;
1097 }
1098
1099
1100 Instr Assembler::ImmShiftLS(unsigned shift_amount) {
1101   ASSERT(is_uint1(shift_amount));
1102   return shift_amount << ImmShiftLS_offset;
1103 }
1104
1105
1106 Instr Assembler::ImmException(int imm16) {
1107   ASSERT(is_uint16(imm16));
1108   return imm16 << ImmException_offset;
1109 }
1110
1111
1112 Instr Assembler::ImmSystemRegister(int imm15) {
1113   ASSERT(is_uint15(imm15));
1114   return imm15 << ImmSystemRegister_offset;
1115 }
1116
1117
1118 Instr Assembler::ImmHint(int imm7) {
1119   ASSERT(is_uint7(imm7));
1120   return imm7 << ImmHint_offset;
1121 }
1122
1123
1124 Instr Assembler::ImmBarrierDomain(int imm2) {
1125   ASSERT(is_uint2(imm2));
1126   return imm2 << ImmBarrierDomain_offset;
1127 }
1128
1129
1130 Instr Assembler::ImmBarrierType(int imm2) {
1131   ASSERT(is_uint2(imm2));
1132   return imm2 << ImmBarrierType_offset;
1133 }
1134
1135
1136 LSDataSize Assembler::CalcLSDataSize(LoadStoreOp op) {
1137   ASSERT((SizeLS_offset + SizeLS_width) == (kInstructionSize * 8));
1138   return static_cast<LSDataSize>(op >> SizeLS_offset);
1139 }
1140
1141
1142 Instr Assembler::ImmMoveWide(uint64_t imm) {
1143   ASSERT(is_uint16(imm));
1144   return imm << ImmMoveWide_offset;
1145 }
1146
1147
1148 Instr Assembler::ShiftMoveWide(int64_t shift) {
1149   ASSERT(is_uint2(shift));
1150   return shift << ShiftMoveWide_offset;
1151 }
1152
1153
1154 Instr Assembler::FPType(FPRegister fd) {
1155   return fd.Is64Bits() ? FP64 : FP32;
1156 }
1157
1158
1159 Instr Assembler::FPScale(unsigned scale) {
1160   ASSERT(is_uint6(scale));
1161   return scale << FPScale_offset;
1162 }
1163
1164
1165 const Register& Assembler::AppropriateZeroRegFor(const CPURegister& reg) const {
1166   return reg.Is64Bits() ? xzr : wzr;
1167 }
1168
1169
1170 void Assembler::LoadRelocated(const CPURegister& rt, const Operand& operand) {
1171   LoadRelocatedValue(rt, operand, LDR_x_lit);
1172 }
1173
1174
1175 inline void Assembler::CheckBufferSpace() {
1176   ASSERT(pc_ < (buffer_ + buffer_size_));
1177   if (buffer_space() < kGap) {
1178     GrowBuffer();
1179   }
1180 }
1181
1182
1183 inline void Assembler::CheckBuffer() {
1184   CheckBufferSpace();
1185   if (pc_offset() >= next_veneer_pool_check_) {
1186     CheckVeneerPool(false, true);
1187   }
1188   if (pc_offset() >= next_constant_pool_check_) {
1189     CheckConstPool(false, true);
1190   }
1191 }
1192
1193
1194 TypeFeedbackId Assembler::RecordedAstId() {
1195   ASSERT(!recorded_ast_id_.IsNone());
1196   return recorded_ast_id_;
1197 }
1198
1199
1200 void Assembler::ClearRecordedAstId() {
1201   recorded_ast_id_ = TypeFeedbackId::None();
1202 }
1203
1204
1205 } }  // namespace v8::internal
1206
1207 #endif  // V8_ARM64_ASSEMBLER_ARM64_INL_H_