7#if defined(TARGET_ARCH_X64)
9#define SHOULD_NOT_INCLUDE_RUNTIME
25 intptr_t far_branch_level)
26 : AssemblerBase(object_pool_builder), constant_pool_allowed_(
false) {
28 ASSERT(far_branch_level == 0);
30 generate_invoke_write_barrier_wrapper_ = [&](
Register reg) {
32 target::Thread::write_barrier_wrappers_thread_offset(reg)));
34 generate_invoke_array_write_barrier_ = [&]() {
36 Address(
THR, target::Thread::array_write_barrier_entry_point_offset()));
41 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
44 EmitLabel(label,
kSize);
47void Assembler::LoadNativeEntry(
49 const ExternalLabel* label,
50 ObjectPoolBuilderEntry::Patchability patchable) {
51 const intptr_t index =
52 object_pool_builder().FindNativeFunction(label, patchable);
53 LoadWordFromPoolIndex(
dst, index);
58 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
60 EmitUint8(0xB8 | (
TMP & 7));
61 EmitInt64(label->address());
66void Assembler::CallCodeThroughPool(intptr_t target_code_pool_index,
74 LoadWordFromPoolIndex(code_reg, target_code_pool_index);
75 call(FieldAddress(code_reg, target::Code::entry_point_offset(entry_kind)));
78void Assembler::CallPatchable(
81 ObjectPoolBuilderEntry::SnapshotBehavior snapshot_behavior) {
82 ASSERT(constant_pool_allowed());
83 const intptr_t idx = object_pool_builder().AddObject(
84 ToObject(
target), ObjectPoolBuilderEntry::kPatchable, snapshot_behavior);
85 CallCodeThroughPool(idx, entry_kind);
88void Assembler::CallWithEquivalence(
const Code&
target,
89 const Object& equivalence,
91 ASSERT(constant_pool_allowed());
94 CallCodeThroughPool(idx, entry_kind);
99 ObjectPoolBuilderEntry::SnapshotBehavior snapshot_behavior) {
100 ASSERT(constant_pool_allowed());
101 const intptr_t idx = object_pool_builder().FindObject(
107void Assembler::pushq(
Register reg) {
108 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
110 EmitUint8(0x50 | (reg & 7));
113void Assembler::pushq(
const Immediate& imm) {
115 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
117 EmitUint8(imm.value() & 0xFF);
118 }
else if (imm.is_int32()) {
119 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
129 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
131 EmitUint8(0x58 | (reg & 7));
136 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
141 EmitUint8(0x90 + condition);
142 EmitUint8(0xC0 + (
dst & 0x07));
145void Assembler::EnterFullSafepoint() {
150 Label
done, slow_path;
151 if (FLAG_use_slow_path || FLAG_target_thread_sanitizer) {
158 movq(
RAX, Immediate(target::Thread::full_safepoint_state_unacquired()));
159 movq(
TMP, Immediate(target::Thread::full_safepoint_state_acquired()));
160 LockCmpxchgq(Address(
THR, target::Thread::safepoint_state_offset()),
TMP);
163 cmpq(
TMP, Immediate(target::Thread::full_safepoint_state_unacquired()));
165 if (!FLAG_use_slow_path && !FLAG_target_thread_sanitizer) {
170 movq(
TMP, Address(
THR, target::Thread::enter_safepoint_stub_offset()));
171 movq(
TMP, FieldAddress(
TMP, target::Code::entry_point_offset()));
181void Assembler::TransitionGeneratedToNative(
Register destination_address,
184 bool enter_safepoint) {
186 movq(Address(
THR, target::Thread::top_exit_frame_info_offset()),
189 movq(compiler::Address(
THR,
190 compiler::target::Thread::exit_through_ffi_offset()),
191 new_exit_through_ffi);
193 movq(Assembler::VMTagAddress(), destination_address);
194 movq(Address(
THR, target::Thread::execution_state_offset()),
195 Immediate(target::Thread::native_execution_state()));
197 if (enter_safepoint) {
198 EnterFullSafepoint();
202void Assembler::ExitFullSafepoint(
bool ignore_unwind_in_progress) {
207 Label
done, slow_path;
208 if (FLAG_use_slow_path || FLAG_target_thread_sanitizer) {
217 movq(
RAX, Immediate(target::Thread::full_safepoint_state_acquired()));
218 movq(
TMP, Immediate(target::Thread::full_safepoint_state_unacquired()));
219 LockCmpxchgq(Address(
THR, target::Thread::safepoint_state_offset()),
TMP);
222 cmpq(
TMP, Immediate(target::Thread::full_safepoint_state_acquired()));
224 if (!FLAG_use_slow_path && !FLAG_target_thread_sanitizer) {
229 if (ignore_unwind_in_progress) {
233 exit_safepoint_ignore_unwind_in_progress_stub_offset()));
235 movq(
TMP, Address(
THR, target::Thread::exit_safepoint_stub_offset()));
237 movq(
TMP, FieldAddress(
TMP, target::Code::entry_point_offset()));
247void Assembler::TransitionNativeToGenerated(
bool leave_safepoint,
248 bool ignore_unwind_in_progress,
250 if (leave_safepoint) {
251 ExitFullSafepoint(ignore_unwind_in_progress);
254 ASSERT(!ignore_unwind_in_progress);
257 movq(
TMP, Address(
THR, target::Thread::safepoint_state_offset()));
258 andq(
TMP, Immediate(target::Thread::full_safepoint_state_acquired()));
267 movq(Assembler::VMTagAddress(),
268 Immediate(target::Thread::vm_tag_dart_id()));
270 movq(Address(
THR, target::Thread::execution_state_offset()),
271 Immediate(target::Thread::generated_execution_state()));
274 movq(Address(
THR, target::Thread::top_exit_frame_info_offset()),
276 movq(compiler::Address(
THR,
277 compiler::target::Thread::exit_through_ffi_offset()),
278 compiler::Immediate(0));
281void Assembler::EmitQ(
int reg,
282 const Address& address,
287 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
291 EmitOperandREX(reg, address,
REX_W);
296 EmitOperand(reg & 7, address);
299void Assembler::EmitL(
int reg,
300 const Address& address,
305 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
309 EmitOperandREX(reg, address,
REX_NONE);
314 EmitOperand(reg & 7, address);
318 const Address& address,
322 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
326 EmitOperandSizeOverride();
327 EmitOperandREX(reg, address,
REX_NONE);
332 EmitOperand(reg & 7, address);
335void Assembler::EmitB(
int reg,
const Address& address,
int opcode) {
336 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
339 EmitOperand(reg & 7, address);
342void Assembler::movl(
Register dst,
const Immediate& imm) {
343 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
344 Operand operand(
dst);
345 EmitOperandREX(0, operand,
REX_NONE);
347 EmitOperand(0, operand);
352void Assembler::movl(
const Address&
dst,
const Immediate& imm) {
357void Assembler::movb(
const Address&
dst,
const Immediate& imm) {
358 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
363 EmitUint8(imm.value() & 0xFF);
370 FATAL(
"Use movzxw or movsxw instead.");
373void Assembler::movw(
const Address&
dst,
const Immediate& imm) {
374 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
375 EmitOperandSizeOverride();
379 EmitUint8(imm.value() & 0xFF);
380 EmitUint8((imm.value() >> 8) & 0xFF);
383void Assembler::movq(
Register dst,
const Immediate& imm) {
384 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
385 if (imm.is_uint32()) {
389 EmitUint8(0xB8 | (
dst & 7));
390 EmitUInt32(imm.value());
391 }
else if (imm.is_int32()) {
393 Operand operand(
dst);
394 EmitOperandREX(0, operand,
REX_W);
396 EmitOperand(0, operand);
401 EmitUint8(0xB8 | (
dst & 7));
406void Assembler::movq(
const Address&
dst,
const Immediate& imm) {
407 if (imm.is_int32()) {
408 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
419void Assembler::EmitSimple(
int opcode,
int opcode2,
int opcode3) {
420 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
430void Assembler::EmitQ(
int dst,
int src,
int opcode,
int prefix2,
int prefix1) {
433 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
442 EmitRegisterOperand(
dst & 7,
src);
445void Assembler::EmitL(
int dst,
int src,
int opcode,
int prefix2,
int prefix1) {
448 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
457 EmitRegisterOperand(
dst & 7,
src);
467 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
471 EmitOperandSizeOverride();
477 EmitRegisterOperand(
dst & 7,
src);
480#define UNARY_XMM_WITH_CONSTANT(name, constant, op) \
481 void Assembler::name(XmmRegister dst, XmmRegister src) { \
482 movq(TMP, Address(THR, target::Thread::constant##_address_offset())); \
484 op(dst, Address(TMP, 0)); \
486 movups(dst, Address(TMP, 0)); \
495UNARY_XMM_WITH_CONSTANT(notps, float_not, xorps)
497UNARY_XMM_WITH_CONSTANT(negateps, float_negate, xorps)
499UNARY_XMM_WITH_CONSTANT(absps, float_absolute, andps)
501UNARY_XMM_WITH_CONSTANT(zerowps, float_zerow, andps)
503UNARY_XMM_WITH_CONSTANT(negatepd, double_negate, xorpd)
505UNARY_XMM_WITH_CONSTANT(abspd, double_abs, andpd)
507UNARY_XMM_WITH_CONSTANT(DoubleNegate, double_negate, xorpd)
509UNARY_XMM_WITH_CONSTANT(DoubleAbs, double_abs, andpd)
511#undef UNARY_XMM_WITH_CONSTANT
514 EmitL(
dst,
src, 0xC2, 0x0F);
515 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
516 EmitUint8(condition);
525 shufps(
dst,
dst, Immediate(0x0));
529 EmitL(
dst,
src, 0xC6, 0x0F);
530 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
532 EmitUint8(imm.value());
536 EmitL(
dst,
src, 0xC6, 0x0F, 0x66);
537 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
539 EmitUint8(imm.value());
545 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
551 EmitRegisterOperand(
dst & 7,
src);
553 EmitUint8(
static_cast<uint8_t
>(
mode) | 0x8);
556void Assembler::fldl(
const Address&
src) {
557 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
562void Assembler::fstpl(
const Address&
dst) {
563 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
568void Assembler::ffree(intptr_t
value) {
570 EmitSimple(0xDD, 0xC0 +
value);
573void Assembler::CompareImmediate(
Register reg,
574 const Immediate& imm,
577 if (imm.is_int32()) {
581 LoadImmediate(
TMP, imm);
590void Assembler::CompareImmediate(
const Address& address,
591 const Immediate& imm,
594 if (imm.is_int32()) {
597 LoadImmediate(
TMP, imm);
606void Assembler::testb(
const Address& address,
const Immediate& imm) {
607 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
608 EmitOperandREX(0, address,
REX_NONE);
610 EmitOperand(0, address);
612 EmitUint8(imm.value() & 0xFF);
615void Assembler::testb(
const Address& address,
Register reg) {
616 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
617 EmitOperandREX(reg, address,
REX_NONE);
619 EmitOperand(reg & 7, address);
622void Assembler::testq(
Register reg,
const Immediate& imm) {
623 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
624 if (imm.is_uint8()) {
629 EmitRegisterREX(reg,
REX_NONE,
true);
635 EmitUint8(0xC0 + (reg & 7));
637 EmitUint8(imm.value() & 0xFF);
638 }
else if (imm.is_uint32()) {
644 EmitUint8(0xC0 | (reg & 7));
646 EmitUInt32(imm.value());
650 EmitRegisterREX(reg,
REX_W);
655 EmitUint8(0xC0 | (reg & 7));
662 const Immediate& imm,
665 if (imm.is_int32() || imm.is_uint32()) {
669 LoadImmediate(
TMP, imm);
678void Assembler::AluL(uint8_t modrm_opcode,
Register dst,
const Immediate& imm) {
679 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
681 EmitComplex(modrm_opcode, Operand(
dst), imm);
684void Assembler::AluB(uint8_t modrm_opcode,
686 const Immediate& imm) {
687 ASSERT(imm.is_uint8() || imm.is_int8());
688 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
691 EmitOperand(modrm_opcode,
dst);
692 EmitUint8(imm.value() & 0xFF);
695void Assembler::AluW(uint8_t modrm_opcode,
697 const Immediate& imm) {
698 ASSERT(imm.is_int16() || imm.is_uint16());
699 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
700 EmitOperandSizeOverride();
703 EmitSignExtendedInt8(modrm_opcode,
dst, imm);
706 EmitOperand(modrm_opcode,
dst);
707 EmitUint8(imm.value() & 0xFF);
708 EmitUint8((imm.value() >> 8) & 0xFF);
712void Assembler::AluL(uint8_t modrm_opcode,
714 const Immediate& imm) {
716 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
718 EmitComplex(modrm_opcode,
dst, imm);
721void Assembler::AluQ(uint8_t modrm_opcode,
724 const Immediate& imm) {
725 Operand operand(
dst);
726 if (modrm_opcode == 4 && imm.is_uint32()) {
728 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
733 EmitSignExtendedInt8(modrm_opcode, operand, imm);
739 EmitOperand(modrm_opcode, operand);
741 EmitUInt32(imm.value());
743 }
else if (imm.is_int32()) {
744 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
746 EmitComplex(modrm_opcode, operand, imm);
754void Assembler::AluQ(uint8_t modrm_opcode,
757 const Immediate& imm) {
758 if (imm.is_int32()) {
759 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
760 EmitOperandREX(modrm_opcode,
dst,
REX_W);
761 EmitComplex(modrm_opcode,
dst, imm);
768void Assembler::AndImmediate(
Register dst,
const Immediate& imm) {
769 if (imm.is_int32() || imm.is_uint32()) {
773 LoadImmediate(
TMP, imm);
785 }
else if (
dst == src2) {
804void Assembler::OrImmediate(
Register dst,
const Immediate& imm) {
805 if (imm.is_int32()) {
809 LoadImmediate(
TMP, imm);
814void Assembler::XorImmediate(
Register dst,
const Immediate& imm) {
815 if (imm.is_int32()) {
819 LoadImmediate(
TMP, imm);
824void Assembler::cqo() {
825 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
830void Assembler::EmitUnaryQ(
Register reg,
int opcode,
int modrm_code) {
831 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
832 EmitRegisterREX(reg,
REX_W);
834 EmitOperand(modrm_code, Operand(reg));
837void Assembler::EmitUnaryL(
Register reg,
int opcode,
int modrm_code) {
838 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
841 EmitOperand(modrm_code, Operand(reg));
844void Assembler::EmitUnaryQ(
const Address& address,
int opcode,
int modrm_code) {
845 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
846 Operand operand(address);
847 EmitOperandREX(modrm_code, operand,
REX_W);
849 EmitOperand(modrm_code, operand);
852void Assembler::EmitUnaryL(
const Address& address,
int opcode,
int modrm_code) {
853 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
854 Operand operand(address);
855 EmitOperandREX(modrm_code, operand,
REX_NONE);
857 EmitOperand(modrm_code, operand);
860void Assembler::imull(
Register reg,
const Immediate& imm) {
861 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
862 Operand operand(reg);
863 EmitOperandREX(reg, operand,
REX_NONE);
865 EmitOperand(reg & 7, Operand(reg));
869void Assembler::imulq(
Register reg,
const Immediate& imm) {
870 if (imm.is_int32()) {
871 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
872 Operand operand(reg);
873 EmitOperandREX(reg, operand,
REX_W);
875 EmitOperand(reg & 7, Operand(reg));
884void Assembler::MulImmediate(
Register reg,
885 const Immediate& imm,
888 if (Utils::IsPowerOfTwo(imm.value())) {
889 const intptr_t shift = Utils::ShiftForPowerOfTwo(imm.value());
891 shll(reg, Immediate(shift));
893 shlq(reg, Immediate(shift));
895 }
else if (imm.is_int32()) {
909void Assembler::shll(
Register reg,
const Immediate& imm) {
910 EmitGenericShift(
false, 4, reg, imm);
914 EmitGenericShift(
false, 4, operand, shifter);
917void Assembler::shrl(
Register reg,
const Immediate& imm) {
918 EmitGenericShift(
false, 5, reg, imm);
922 EmitGenericShift(
false, 5, operand, shifter);
925void Assembler::sarl(
Register reg,
const Immediate& imm) {
926 EmitGenericShift(
false, 7, reg, imm);
930 EmitGenericShift(
false, 7, operand, shifter);
934 EmitL(
src,
dst, 0xA4, 0x0F);
935 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
937 EmitUint8(imm.value() & 0xFF);
940void Assembler::shlq(
Register reg,
const Immediate& imm) {
941 EmitGenericShift(
true, 4, reg, imm);
945 EmitGenericShift(
true, 4, operand, shifter);
948void Assembler::shrq(
Register reg,
const Immediate& imm) {
949 EmitGenericShift(
true, 5, reg, imm);
953 EmitGenericShift(
true, 5, operand, shifter);
956void Assembler::sarq(
Register reg,
const Immediate& imm) {
957 EmitGenericShift(
true, 7, reg, imm);
961 EmitGenericShift(
true, 7, operand, shifter);
965 EmitQ(
src,
dst, 0xA4, 0x0F);
966 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
968 EmitUint8(imm.value() & 0xFF);
972 ASSERT(bit >= 0 && bit < 64);
973 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
974 Operand operand(
base);
978 EmitOperand(4, operand);
982void Assembler::enter(
const Immediate& imm) {
983 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
986 EmitUint8(imm.value() & 0xFF);
987 EmitUint8((imm.value() >> 8) & 0xFF);
991void Assembler::nop(
int size) {
992 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
1054 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
1055 if (label->IsBound()) {
1056 const int kShortSize = 2;
1057 const int kLongSize = 6;
1058 intptr_t
offset = label->Position() - buffer_.Size();
1060 if (Utils::IsInt(8,
offset - kShortSize)) {
1061 EmitUint8(0x70 + condition);
1062 EmitUint8((
offset - kShortSize) & 0xFF);
1065 EmitUint8(0x80 + condition);
1066 EmitInt32(
offset - kLongSize);
1068 }
else if (
distance == kNearJump) {
1069 EmitUint8(0x70 + condition);
1070 EmitNearLabelLink(label);
1073 EmitUint8(0x80 + condition);
1074 EmitLabelLink(label);
1081 j(
static_cast<Condition>(condition ^ 1), &no_jump, kNearJump);
1086void Assembler::jmp(Label* label, JumpDistance
distance) {
1087 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
1088 if (label->IsBound()) {
1089 const int kShortSize = 2;
1090 const int kLongSize = 5;
1091 intptr_t
offset = label->Position() - buffer_.Size();
1093 if (Utils::IsInt(8,
offset - kShortSize)) {
1095 EmitUint8((
offset - kShortSize) & 0xFF);
1098 EmitInt32(
offset - kLongSize);
1100 }
else if (
distance == kNearJump) {
1102 EmitNearLabelLink(label);
1105 EmitLabelLink(label);
1109void Assembler::jmp(
const ExternalLabel* label) {
1111 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
1113 EmitUint8(0xB8 | (
TMP & 7));
1114 EmitInt64(label->address());
1120 ASSERT((pp !=
PP) || constant_pool_allowed());
1121 const intptr_t idx = object_pool_builder().AddObject(
1123 const int32_t
offset = target::ObjectPool::element_offset(idx);
1125 movq(
TMP, FieldAddress(
CODE_REG, target::Code::entry_point_offset()));
1130 ASSERT((pp !=
PP) || constant_pool_allowed());
1131 const intptr_t idx = object_pool_builder().FindObject(
1133 const int32_t
offset = target::ObjectPool::element_offset(idx);
1135 jmp(FieldAddress(
CODE_REG, target::Code::entry_point_offset()));
1142void Assembler::LoadFromStack(
Register dst, intptr_t depth) {
1147void Assembler::StoreToStack(
Register src, intptr_t depth) {
1152void Assembler::CompareToStack(
Register src, intptr_t depth) {
1160 if (to == from)
return;
1161 return movq(to, from);
1163 return movl(to, from);
1165 return movsxd(to, from);
1167 return movzxw(to, from);
1169 return movsxw(to, from);
1171 return movzxb(to, from);
1173 return movsxb(to, from);
1180void Assembler::PushRegister(
Register r) {
1184void Assembler::PopRegister(
Register r) {
1188void Assembler::AddImmediate(
Register reg,
1189 const Immediate& imm,
1192 const int64_t
value = imm.value();
1213 LoadImmediate(
TMP, imm);
1231 if (Utils::IsInt(32,
value)) {
1239void Assembler::AddImmediate(
const Address& address,
const Immediate& imm) {
1240 const int64_t
value = imm.value();
1248 if (imm.is_int32()) {
1251 LoadImmediate(
TMP, imm);
1256 SubImmediate(address, Immediate(-
value));
1260void Assembler::SubImmediate(
Register reg,
1261 const Immediate& imm,
1264 const int64_t
value = imm.value();
1277 if (imm.is_int32()) {
1286 LoadImmediate(
TMP, imm);
1295void Assembler::SubImmediate(
const Address& address,
const Immediate& imm) {
1296 const int64_t
value = imm.value();
1304 if (imm.is_int32()) {
1307 LoadImmediate(
TMP, imm);
1312 AddImmediate(address, Immediate(-
value));
1316void Assembler::Drop(intptr_t stack_elements,
Register tmp) {
1317 ASSERT(stack_elements >= 0);
1318 if (stack_elements <= 4) {
1319 for (intptr_t
i = 0;
i < stack_elements;
i++) {
1327bool Assembler::CanLoadFromObjectPool(
const Object&
object)
const {
1329 if (!constant_pool_allowed()) {
1338void Assembler::LoadWordFromPoolIndex(
Register dst, intptr_t idx) {
1339 ASSERT(constant_pool_allowed());
1342 movq(
dst, FieldAddress(
PP, target::ObjectPool::element_offset(idx)));
1345void Assembler::StoreWordToPoolIndex(
Register src, intptr_t idx) {
1346 ASSERT(constant_pool_allowed());
1349 movq(FieldAddress(
PP, target::ObjectPool::element_offset(idx)),
src);
1353 compiler::Label
done;
1354#if !defined(DART_COMPRESSED_POINTERS)
1361 target::Mint::value_offset()));
1373 movq(
result, compiler::FieldAddress(
value, target::Mint::value_offset()));
1379 compiler::Label
done;
1380#if !defined(DART_COMPRESSED_POINTERS)
1387 compiler::target::Mint::value_offset()));
1400 compiler::FieldAddress(
value, compiler::target::Mint::value_offset()));
1406 movq(
dst, Address(
THR, target::Thread::isolate_offset()));
1410 movq(
dst, Address(
THR, target::Thread::isolate_group_offset()));
1414 movq(
dst, Address(
THR, target::Thread::dispatch_table_array_offset()));
1417void Assembler::LoadObjectHelper(
1419 const Object&
object,
1421 ObjectPoolBuilderEntry::SnapshotBehavior snapshot_behavior) {
1437 const intptr_t index =
1439 ? object_pool_builder().AddObject(
1440 object, ObjectPoolBuilderEntry::kPatchable, snapshot_behavior)
1441 : object_pool_builder().FindObject(
1442 object, ObjectPoolBuilderEntry::kNotPatchable,
1444 LoadWordFromPoolIndex(
dst, index);
1447void Assembler::LoadObject(
Register dst,
const Object&
object) {
1448 LoadObjectHelper(
dst,
object,
false);
1451void Assembler::LoadUniqueObject(
1453 const Object&
object,
1454 ObjectPoolBuilderEntry::SnapshotBehavior snapshot_behavior) {
1455 LoadObjectHelper(
dst,
object,
true, snapshot_behavior);
1458void Assembler::StoreObject(
const Address&
dst,
1459 const Object&
object,
1464 intptr_t offset_from_thread;
1466 movq(
TMP, Address(
THR, offset_from_thread));
1471 LoadObject(
TMP,
object);
1476void Assembler::PushObject(
const Object&
object) {
1479 intptr_t offset_from_thread;
1481 pushq(Address(
THR, offset_from_thread));
1485 LoadObject(
TMP,
object);
1490void Assembler::CompareObject(
Register reg,
const Object&
object) {
1493 intptr_t offset_from_thread;
1495 OBJ(cmp)(reg, Address(
THR, offset_from_thread));
1500 const intptr_t idx = object_pool_builder().FindObject(
1501 object, ObjectPoolBuilderEntry::kNotPatchable);
1502 const int32_t
offset = target::ObjectPool::element_offset(idx);
1507void Assembler::LoadImmediate(
Register reg,
const Immediate& imm) {
1508 if (imm.value() == 0) {
1510 }
else if (imm.is_int32() || !constant_pool_allowed()) {
1513 const intptr_t idx = object_pool_builder().FindImmediate(imm.value());
1514 LoadWordFromPoolIndex(reg, idx);
1518void Assembler::MoveImmediate(
const Address&
dst,
1519 const Immediate& imm,
1521 if (imm.is_int32()) {
1529 LoadImmediate(
TMP, imm);
1539void Assembler::LoadSImmediate(
FpuRegister dst,
float immediate) {
1540 int32_t
bits = bit_cast<int32_t>(immediate);
1544 intptr_t index = object_pool_builder().FindImmediate(
bits);
1550void Assembler::LoadDImmediate(
FpuRegister dst,
double immediate) {
1551 int64_t
bits = bit_cast<int64_t>(immediate);
1555 intptr_t index = object_pool_builder().FindImmediate64(
bits);
1561void Assembler::LoadQImmediate(
FpuRegister dst, simd128_value_t immediate) {
1562 intptr_t index = object_pool_builder().FindImmediate128(immediate);
1563 movups(
dst, Address(
PP, target::ObjectPool::element_offset(index) -
1567#if defined(DART_COMPRESSED_POINTERS)
1568void Assembler::LoadCompressed(
Register dest,
const Address& slot) {
1570 addq(
dest, Address(
THR, target::Thread::heap_base_offset()));
1574void Assembler::StoreBarrier(
Register object,
1576 CanBeSmi can_be_smi,
1580 ASSERT(
object != scratch);
1592 if (can_be_smi == kValueCanBeSmi) {
1597 BranchIfNotSmi(
value, &passed_check, kNearJump);
1599 Bind(&passed_check);
1603 FieldAddress(
object, target::Object::tags_offset()));
1604 shrl(scratch, Immediate(target::UntaggedObject::kBarrierOverlapShift));
1605 andl(scratch, Address(
THR, target::Thread::write_barrier_mask_offset()));
1606 testb(FieldAddress(
value, target::Object::tags_offset()), scratch);
1618 pushq(object_for_call);
1619 movq(object_for_call,
object);
1623 generate_invoke_write_barrier_wrapper_(object_for_call);
1626 popq(object_for_call);
1633void Assembler::ArrayStoreBarrier(
Register object,
1636 CanBeSmi can_be_smi,
1638 ASSERT(
object != scratch);
1651 if (can_be_smi == kValueCanBeSmi) {
1656 BranchIfNotSmi(
value, &passed_check, kNearJump);
1658 Bind(&passed_check);
1662 FieldAddress(
object, target::Object::tags_offset()));
1663 shrl(scratch, Immediate(target::UntaggedObject::kBarrierOverlapShift));
1664 andl(scratch, Address(
THR, target::Thread::write_barrier_mask_offset()));
1665 testb(FieldAddress(
value, target::Object::tags_offset()), scratch);
1676 generate_invoke_array_write_barrier_();
1681void Assembler::VerifyStoreNeedsNoWriteBarrier(
Register object,
1690 testb(FieldAddress(
value, target::Object::tags_offset()),
1691 Immediate(1 << target::UntaggedObject::kNewOrEvacuationCandidateBit));
1692 j(
ZERO, &
done, Assembler::kNearJump);
1693 testb(FieldAddress(
object, target::Object::tags_offset()),
1694 Immediate(1 << target::UntaggedObject::kOldAndNotRememberedBit));
1695 j(
ZERO, &
done, Assembler::kNearJump);
1696 Stop(
"Write barrier is required");
1700void Assembler::StoreObjectIntoObjectNoBarrier(
Register object,
1701 const Address&
dest,
1702 const Object&
value,
1703 MemoryOrder memory_order,
1705 if (memory_order == kRelease) {
1707 StoreIntoObjectNoBarrier(
object,
dest,
TMP, memory_order,
size);
1713void Assembler::StoreInternalPointer(
Register object,
1714 const Address&
dest,
1724 Stop(
"New value must be Smi.");
1730void Assembler::ZeroInitSmiField(
const Address&
dest) {
1735void Assembler::ZeroInitCompressedSmiField(
const Address&
dest) {
1740void Assembler::IncrementCompressedSmiField(
const Address&
dest,
1741 int64_t increment) {
1749 intptr_t bound = buffer_.Size();
1750 ASSERT(!label->IsBound());
1751 while (label->IsLinked()) {
1752 intptr_t position = label->LinkPosition();
1753 intptr_t
next = buffer_.Load<int32_t>(position);
1754 buffer_.Store<int32_t>(position, bound - (position + 4));
1755 label->position_ =
next;
1757 while (label->HasNear()) {
1758 intptr_t position = label->NearPosition();
1759 intptr_t
offset = bound - (position + 1);
1761 buffer_.Store<int8_t>(position,
offset);
1763 label->BindTo(bound);
1769 return movsxb(reg, address);
1771 return movzxb(reg, address);
1773 return movsxw(reg, address);
1775 return movzxw(reg, address);
1777 return movsxd(reg, address);
1779 return movl(reg, address);
1781 return movq(reg, address);
1795 return movw(address, reg);
1798 return movl(address, reg);
1800 return movq(address, reg);
1807void Assembler::ArithmeticShiftRightImmediate(
Register reg, intptr_t shift) {
1808 sarq(reg, Immediate(shift));
1811void Assembler::CompareWords(
Register reg1,
1824 BranchIf(
EQUAL, &loop, Assembler::kNearJump);
1827void Assembler::EnterFrame(intptr_t frame_size) {
1828 if (prologue_offset_ == -1) {
1829 prologue_offset_ = CodeSize();
1830 Comment(
"PrologueOffset = %" Pd "", CodeSize());
1833 intptr_t check_offset = CodeSize();
1838 ProloguePattern pp(CodeAddress(check_offset));
1841 if (frame_size != 0) {
1842 Immediate frame_space(frame_size);
1843 subq(
RSP, frame_space);
1847void Assembler::LeaveFrame() {
1852void Assembler::ReserveAlignedFrameSpace(intptr_t frame_space) {
1855 if (frame_space != 0) {
1856 subq(
RSP, Immediate(frame_space));
1858 if (OS::ActivationFrameAlignment() > 1) {
1859 andq(
RSP, Immediate(~(OS::ActivationFrameAlignment() - 1)));
1863void Assembler::EmitEntryFrameVerification() {
1870 Stop(
"target::frame_layout.exit_link_slot_from_entry_fp mismatch");
1875void Assembler::PushRegisters(
const RegisterSet& register_set) {
1876 const intptr_t xmm_regs_count = register_set.FpuRegisterCount();
1877 if (xmm_regs_count > 0) {
1884 if (register_set.ContainsFpuRegister(xmm_reg)) {
1896 if (register_set.ContainsRegister(reg)) {
1902void Assembler::PopRegisters(
const RegisterSet& register_set) {
1905 if (register_set.ContainsRegister(reg)) {
1910 const intptr_t xmm_regs_count = register_set.FpuRegisterCount();
1911 if (xmm_regs_count > 0) {
1916 if (register_set.ContainsFpuRegister(xmm_reg)) {
1926void Assembler::PushRegistersInOrder(std::initializer_list<Register> regs) {
1932static const RegisterSet kVolatileRegisterSet(
1933 CallingConventions::kVolatileCpuRegisters,
1934 CallingConventions::kVolatileXmmRegisters);
1936void Assembler::CallCFunction(
Register reg,
bool restore_rsp) {
1938 if (CallingConventions::kShadowSpaceBytes != 0) {
1939 subq(
RSP, Immediate(CallingConventions::kShadowSpaceBytes));
1943 if (restore_rsp && CallingConventions::kShadowSpaceBytes != 0) {
1944 addq(
RSP, Immediate(CallingConventions::kShadowSpaceBytes));
1947void Assembler::CallCFunction(Address address,
bool restore_rsp) {
1949 if (CallingConventions::kShadowSpaceBytes != 0) {
1950 subq(
RSP, Immediate(CallingConventions::kShadowSpaceBytes));
1954 if (restore_rsp && CallingConventions::kShadowSpaceBytes != 0) {
1955 addq(
RSP, Immediate(CallingConventions::kShadowSpaceBytes));
1959void Assembler::CallRuntime(
const RuntimeEntry& entry,
1961 ASSERT(!entry.is_leaf());
1964 movq(
RBX, compiler::Address(
THR, entry.OffsetFromThread()));
1966 call(Address(
THR, target::Thread::call_to_runtime_entry_point_offset()));
1969#define __ assembler_->
1971LeafRuntimeScope::LeafRuntimeScope(Assembler* assembler,
1972 intptr_t frame_size,
1973 bool preserve_registers)
1974 : assembler_(assembler), preserve_registers_(preserve_registers) {
1975 __ Comment(
"EnterCallRuntimeFrame");
1978 if (preserve_registers_) {
1980 __ PushRegisters(kVolatileRegisterSet);
1988 __ ReserveAlignedFrameSpace(frame_size);
1991void LeafRuntimeScope::Call(
const RuntimeEntry& entry,
1996 __ movq(
RAX, compiler::Address(
THR, entry.OffsetFromThread()));
1997 __ movq(compiler::Assembler::VMTagAddress(),
RAX);
1998 __ CallCFunction(
RAX);
1999 __ movq(compiler::Assembler::VMTagAddress(),
2000 compiler::Immediate(VMTag::kDartTagId));
2003LeafRuntimeScope::~LeafRuntimeScope() {
2004 if (preserve_registers_) {
2008 const intptr_t kPushedCpuRegistersCount =
2009 RegisterSet::RegisterCount(CallingConventions::kVolatileCpuRegisters);
2010 const intptr_t kPushedXmmRegistersCount =
2011 RegisterSet::RegisterCount(CallingConventions::kVolatileXmmRegisters);
2012 const intptr_t kPushedRegistersSize =
2016 __ leaq(
RSP, Address(
RBP, -kPushedRegistersSize));
2019 __ PopRegisters(kVolatileRegisterSet);
2021 const intptr_t kPushedRegistersSize =
2024 __ leaq(
RSP, Address(
RBP, -kPushedRegistersSize));
2030void Assembler::TsanLoadAcquire(Address
addr) {
2031 LeafRuntimeScope rt(
this, 0,
true);
2033 rt.Call(kTsanLoadAcquireRuntimeEntry, 1);
2036void Assembler::TsanStoreRelease(Address
addr) {
2037 LeafRuntimeScope rt(
this, 0,
true);
2039 rt.Call(kTsanStoreReleaseRuntimeEntry, 1);
2042void Assembler::RestoreCodePointer() {
2047void Assembler::LoadPoolPointer(
Register pp) {
2050 movq(pp, FieldAddress(
CODE_REG, target::Code::object_pool_offset()));
2051 set_constant_pool_allowed(pp ==
PP);
2054void Assembler::EnterDartFrame(intptr_t frame_size,
Register new_pp) {
2055 ASSERT(!constant_pool_allowed());
2057 if (!FLAG_precompiled_mode) {
2061 LoadPoolPointer(
PP);
2066 set_constant_pool_allowed(
true);
2067 if (frame_size != 0) {
2068 subq(
RSP, Immediate(frame_size));
2072void Assembler::LeaveDartFrame() {
2074 if (!FLAG_precompiled_mode) {
2078 set_constant_pool_allowed(
false);
2082void Assembler::CheckCodePointer() {
2084 if (!FLAG_check_code_pointer) {
2087 Comment(
"CheckCodePointer");
2088 Label cid_ok, instructions_ok;
2091 cmpq(
RAX, Immediate(kCodeCid));
2096 const intptr_t kRIPRelativeLeaqSize = 7;
2097 const intptr_t header_to_entry_offset =
2099 const intptr_t header_to_rip_offset =
2100 CodeSize() + kRIPRelativeLeaqSize + header_to_entry_offset;
2101 leaq(
RAX, Address::AddressRIPRelative(-header_to_rip_offset));
2102 ASSERT(CodeSize() == (header_to_rip_offset - header_to_entry_offset));
2104 cmpq(
RAX, FieldAddress(
CODE_REG, target::Code::instructions_offset()));
2105 j(
EQUAL, &instructions_ok);
2107 Bind(&instructions_ok);
2117void Assembler::EnterOsrFrame(intptr_t extra_size) {
2118 ASSERT(!constant_pool_allowed());
2119 if (prologue_offset_ == -1) {
2120 Comment(
"PrologueOffset = %" Pd "", CodeSize());
2121 prologue_offset_ = CodeSize();
2123 RestoreCodePointer();
2126 if (extra_size != 0) {
2127 subq(
RSP, Immediate(extra_size));
2131void Assembler::EnterStubFrame() {
2135void Assembler::LeaveStubFrame() {
2139void Assembler::EnterCFrame(intptr_t frame_space) {
2145 ReserveAlignedFrameSpace(frame_space);
2148void Assembler::LeaveCFrame() {
2154void Assembler::MonomorphicCheckedEntryJIT() {
2155 has_monomorphic_entry_ =
true;
2156 intptr_t
start = CodeSize();
2157 Label have_cid, miss;
2159 jmp(Address(
THR, target::Thread::switchable_call_miss_entry_offset()));
2165 Comment(
"MonomorphicCheckedEntry");
2167 target::Instructions::kMonomorphicEntryOffsetJIT);
2170 const intptr_t cid_offset = target::Array::element_offset(0);
2171 const intptr_t count_offset = target::Array::element_offset(1);
2173 LoadTaggedClassIdMayBeSmi(
RAX,
RDX);
2175 OBJ(cmp)(
RAX, FieldAddress(
RBX, cid_offset));
2176 j(
NOT_EQUAL, &miss, Assembler::kNearJump);
2179#if defined(DART_COMPRESSED_POINTERS)
2187 target::Instructions::kPolymorphicEntryOffsetJIT);
2193void Assembler::MonomorphicCheckedEntryAOT() {
2194 has_monomorphic_entry_ =
true;
2195 intptr_t
start = CodeSize();
2196 Label have_cid, miss;
2198 jmp(Address(
THR, target::Thread::switchable_call_miss_entry_offset()));
2204 Comment(
"MonomorphicCheckedEntry");
2206 target::Instructions::kMonomorphicEntryOffsetAOT);
2212 j(
NOT_EQUAL, &miss, Assembler::kNearJump);
2216#if defined(DART_COMPRESSED_POINTERS)
2222 target::Instructions::kPolymorphicEntryOffsetAOT);
2226void Assembler::BranchOnMonomorphicCheckedEntryJIT(Label* label) {
2227 has_monomorphic_entry_ =
true;
2228 while (CodeSize() < target::Instructions::kMonomorphicEntryOffsetJIT) {
2232 while (CodeSize() < target::Instructions::kPolymorphicEntryOffsetJIT) {
2242 shll(other, Immediate(10));
2246 shrl(other, Immediate(6));
2250void Assembler::FinalizeHashForSize(intptr_t bit_size,
2260 shll(scratch, Immediate(3));
2264 shrl(scratch, Immediate(11));
2268 shll(scratch, Immediate(15));
2272 andl(
dst, Immediate(Utils::NBitMask(bit_size)));
2290 LoadIsolateGroup(temp_reg);
2291 movq(temp_reg, Address(temp_reg, target::IsolateGroup::class_table_offset()));
2295 target::ClassTable::allocation_tracing_state_table_offset()));
2297 target::ClassTable::AllocationTracingStateSlotOffsetFor(0)),
2304void Assembler::MaybeTraceAllocation(intptr_t
cid,
2313 LoadIsolateGroup(temp_reg);
2314 movq(temp_reg, Address(temp_reg, target::IsolateGroup::class_table_offset()));
2317 target::ClassTable::allocation_tracing_state_table_offset()));
2318 cmpb(Address(temp_reg,
2319 target::ClassTable::AllocationTracingStateSlotOffsetFor(
cid)),
2327void Assembler::TryAllocateObject(intptr_t
cid,
2328 intptr_t instance_size,
2333 ASSERT(failure !=
nullptr);
2334 ASSERT(instance_size != 0);
2335 ASSERT(Utils::IsAligned(instance_size,
2337 if (FLAG_inline_alloc &&
2343 movq(instance_reg, Address(
THR, target::Thread::top_offset()));
2344 addq(instance_reg, Immediate(instance_size));
2346 cmpq(instance_reg, Address(
THR, target::Thread::end_offset()));
2348 CheckAllocationCanary(instance_reg);
2351 movq(Address(
THR, target::Thread::top_offset()), instance_reg);
2353 AddImmediate(instance_reg, Immediate(
kHeapObjectTag - instance_size));
2355 MoveImmediate(FieldAddress(instance_reg, target::Object::tags_offset()),
2362void Assembler::TryAllocateArray(intptr_t
cid,
2363 intptr_t instance_size,
2369 ASSERT(failure !=
nullptr);
2370 if (FLAG_inline_alloc &&
2376 movq(
instance, Address(
THR, target::Thread::top_offset()));
2379 addq(end_address, Immediate(instance_size));
2385 cmpq(end_address, Address(
THR, target::Thread::end_offset()));
2391 movq(Address(
THR, target::Thread::top_offset()), end_address);
2397 movq(FieldAddress(
instance, target::Object::tags_offset()),
2413 cmpq(
size, Immediate(0));
2416 movq(temp, Address(
src, 0));
2418 movq(Address(
dst, 0), temp);
2425void Assembler::GenerateUnRelocatedPcRelativeCall(intptr_t offset_into_target) {
2426 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
2427 buffer_.Emit<uint8_t>(0xe8);
2428 buffer_.Emit<int32_t>(0);
2430 PcRelativeCallPattern pattern(buffer_.contents() + buffer_.Size() -
2431 PcRelativeCallPattern::kLengthInBytes);
2432 pattern.set_distance(offset_into_target);
2435void Assembler::GenerateUnRelocatedPcRelativeTailCall(
2436 intptr_t offset_into_target) {
2437 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
2438 buffer_.Emit<uint8_t>(0xe9);
2439 buffer_.Emit<int32_t>(0);
2441 PcRelativeCallPattern pattern(buffer_.contents() + buffer_.Size() -
2442 PcRelativeCallPattern::kLengthInBytes);
2443 pattern.set_distance(offset_into_target);
2447 ASSERT(Utils::IsPowerOfTwo(alignment));
2448 intptr_t
pos =
offset + buffer_.GetPosition();
2449 int mod =
pos & (alignment - 1);
2461 ASSERT(((
offset + buffer_.GetPosition()) & (alignment - 1)) == 0);
2464void Assembler::EmitOperand(
int rm,
const Operand& operand) {
2465 ASSERT(rm >= 0 && rm < 8);
2466 const intptr_t
length = operand.length_;
2469 ASSERT((operand.encoding_[0] & 0x38) == 0);
2470 EmitUint8(operand.encoding_[0] + (rm << 3));
2473 EmitUint8(operand.encoding_[
i]);
2477void Assembler::EmitRegisterOperand(
int rm,
int reg) {
2479 operand.SetModRM(3,
static_cast<Register>(reg));
2480 EmitOperand(rm, operand);
2483void Assembler::EmitImmediate(
const Immediate& imm) {
2484 if (imm.is_int32()) {
2485 EmitInt32(
static_cast<int32_t
>(imm.value()));
2487 EmitInt64(imm.value());
2491void Assembler::EmitSignExtendedInt8(
int rm,
2492 const Operand& operand,
2493 const Immediate& immediate) {
2495 EmitOperand(rm, operand);
2496 EmitUint8(immediate.value() & 0xFF);
2499void Assembler::EmitComplex(
int rm,
2500 const Operand& operand,
2501 const Immediate& immediate) {
2502 ASSERT(rm >= 0 && rm < 8);
2503 ASSERT(immediate.is_int32());
2504 if (immediate.is_int8()) {
2505 EmitSignExtendedInt8(rm, operand, immediate);
2506 }
else if (operand.IsRegister(
RAX)) {
2508 EmitUint8(0x05 + (rm << 3));
2509 EmitImmediate(immediate);
2512 EmitOperand(rm, operand);
2513 EmitImmediate(immediate);
2517void Assembler::EmitLabel(Label* label, intptr_t instruction_size) {
2518 if (label->IsBound()) {
2519 intptr_t
offset = label->Position() - buffer_.Size();
2521 EmitInt32(
offset - instruction_size);
2523 EmitLabelLink(label);
2527void Assembler::EmitLabelLink(Label* label) {
2528 ASSERT(!label->IsBound());
2529 intptr_t position = buffer_.Size();
2530 EmitInt32(label->position_);
2531 label->LinkTo(position);
2534void Assembler::EmitNearLabelLink(Label* label) {
2535 ASSERT(!label->IsBound());
2536 intptr_t position = buffer_.Size();
2538 label->NearLinkTo(position);
2541void Assembler::EmitGenericShift(
bool wide,
2544 const Immediate& imm) {
2545 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
2548 EmitRegisterREX(reg,
REX_W);
2552 if (imm.value() == 1) {
2554 EmitOperand(rm, Operand(reg));
2557 EmitOperand(rm, Operand(reg));
2558 EmitUint8(imm.value() & 0xFF);
2562void Assembler::EmitGenericShift(
bool wide,
2566 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
2570 EmitOperand(rm, Operand(operand));
2574 ASSERT(target::UntaggedObject::kClassIdTagPos == 12);
2575 ASSERT(target::UntaggedObject::kClassIdTagSize == 20);
2577 shrl(
result, Immediate(12));
2581 ASSERT(target::UntaggedObject::kSizeTagPos == 8);
2582 ASSERT(target::UntaggedObject::kSizeTagSize == 4);
2584 shrl(
result, Immediate(target::UntaggedObject::kSizeTagPos -
2587 Immediate(Utils::NBitMask(target::UntaggedObject::kSizeTagSize)
2592 ASSERT(target::UntaggedObject::kClassIdTagPos == 12);
2593 ASSERT(target::UntaggedObject::kClassIdTagSize == 20);
2594 movl(
result, FieldAddress(
object, target::Object::tags_offset()));
2595 shrl(
result, Immediate(target::UntaggedObject::kClassIdTagPos));
2600 const intptr_t table_offset =
2601 target::IsolateGroup::cached_class_table_table_offset();
2603 LoadIsolateGroup(
result);
2608void Assembler::CompareClassId(
Register object,
2611 LoadClassId(
TMP,
object);
2612 cmpl(
TMP, Immediate(class_id));
2615void Assembler::SmiUntagOrCheckClass(
Register object,
2618#if !defined(DART_COMPRESSED_POINTERS)
2620 ASSERT(target::UntaggedObject::kClassIdTagPos == 12);
2621 ASSERT(target::UntaggedObject::kClassIdTagSize == 20);
2629 shrl(
TMP, Immediate(target::UntaggedObject::kClassIdTagPos));
2630 cmpl(
TMP, Immediate(class_id));
2645 j(
EQUAL, &smi, Assembler::kNearJump);
2646 LoadClassId(
result,
object);
2647 jmp(&
join, Assembler::kNearJump);
2650 movq(
result, Immediate(kSmiCid));
2655 movq(
result, Immediate(kSmiCid));
2656 j(
EQUAL, &smi, Assembler::kNearJump);
2657 LoadClassId(
result,
object);
2670 j(
EQUAL, &smi, Assembler::kNearJump);
2671 LoadClassId(
result,
object);
2673 jmp(&
join, Assembler::kNearJump);
2682 j(
EQUAL, &smi, Assembler::kNearJump);
2683 LoadClassId(
result,
object);
2690void Assembler::EnsureHasClassIdInDEBUG(intptr_t
cid,
2695 Comment(
"Check that object in register has cid %" Pd "",
cid);
2697 LoadClassIdMayBeSmi(scratch,
src);
2698 CompareImmediate(scratch,
cid);
2701 CompareImmediate(scratch,
kNullCid);
2709Address Assembler::VMTagAddress() {
2710 return Address(
THR, target::Thread::vm_tag_offset());
2713bool Assembler::AddressCanHoldConstantIndex(
const Object& constant,
2716 intptr_t index_scale) {
2717 if (!IsSafeSmi(constant))
return false;
2719 const int64_t disp =
2720 index * index_scale +
2722 return Utils::IsInt(32, disp);
2725Address Assembler::ElementAddressForIntIndex(
bool is_external,
2727 intptr_t index_scale,
2731 return Address(array, index * index_scale);
2733 const int64_t disp =
static_cast<int64_t
>(index) * index_scale +
2734 target::Instance::DataOffsetFor(
cid);
2735 ASSERT(Utils::IsInt(32, disp));
2736 return FieldAddress(array,
static_cast<int32_t
>(disp));
2740Address Assembler::ElementAddressForRegIndex(
bool is_external,
2742 intptr_t index_scale,
2747 return Address(array, index,
ToScaleFactor(index_scale, index_unboxed), 0);
2749 return FieldAddress(array, index,
ToScaleFactor(index_scale, index_unboxed),
2750 target::Instance::DataOffsetFor(
cid));
2758 RangeCheckCondition condition,
2766 subq(to_check, Immediate(low));
2767 cmpq(to_check, Immediate(high - low));
static void done(const char *config, const char *src, const char *srcOptions, const char *name)
static float next(float f)
static bool ok(int result)
bool equals(SkDrawable *a, SkDrawable *b)
#define DEBUG_ASSERT(cond)
#define ASSERT_EQUAL(expected, actual)
#define RELEASE_ASSERT(cond)
#define COMPILE_ASSERT(expr)
Assembler(ObjectPoolBuilder *object_pool_builder, intptr_t far_branch_level=0)
@ kNormal
Default priority level.
uword MakeTagWordForNewSpaceObject(classid_t cid, uword instance_size)
bool CanLoadFromThread(const dart::Object &object, intptr_t *offset)
word ToRawSmi(const dart::Object &a)
word SmiValue(const dart::Object &a)
bool IsOriginalObject(const Object &object)
InvalidClass kObjectAlignment
InvalidClass kObjectAlignmentLog2
bool IsInOldSpace(const Object &obj)
constexpr OperandSize kWordBytes
const Object & ToObject(const Code &handle)
static constexpr int HeaderSize
constexpr int64_t kMinInt64
const Register kWriteBarrierSlotReg
const Register kWriteBarrierObjectReg
constexpr int32_t kMinInt32
const Register kWriteBarrierValueReg
static constexpr bool IsCalleeSavedRegister(Register reg)
uint32_t CombineHashes(uint32_t hash, uint32_t other_hash)
bool IsAllocatableInNewSpace(intptr_t size)
constexpr intptr_t kBitsPerInt32
constexpr intptr_t kWordSize
static ScaleFactor ToScaleFactor(intptr_t index_scale, bool index_unboxed)
const int kFpuRegisterSize
DECLARE_FLAG(bool, show_invisible_frames)
ByteRegister ByteRegisterOf(Register reg)
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive mode
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
static size_t bytes_needed(int vertex_count, Flags flags, int index_count)
static bool Bind(PassBindingsCacheMTL &pass, ShaderStage stage, size_t bind_index, const BufferView &view)
static SkString join(const CommandLineFlags::StringArray &)
intptr_t dart_fixed_frame_size
#define NOT_IN_PRODUCT(code)