8#if defined(TARGET_ARCH_X64) || defined(TARGET_ARCH_IA32)
24#if !defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER)
29 REG_OPER_OP_ORDER = 1,
30 OPER_REG_OP_ORDER = 2,
32 BYTE_SIZE_OPERAND_FLAG = 4,
33 BYTE_REG_OPER_OP_ORDER = REG_OPER_OP_ORDER | BYTE_SIZE_OPERAND_FLAG,
34 BYTE_OPER_REG_OP_ORDER = OPER_REG_OP_ORDER | BYTE_SIZE_OPERAND_FLAG
42 OperandType op_order_;
46#define ALU_ENTRY(name, code) \
47 {code * 8 + 0, BYTE_OPER_REG_OP_ORDER, #name}, \
48 {code * 8 + 1, OPER_REG_OP_ORDER, #name}, \
49 {code * 8 + 2, BYTE_REG_OPER_OP_ORDER, #name}, \
50 {code * 8 + 3, REG_OPER_OP_ORDER, #name},
51static const ByteMnemonic two_operands_instr[] = {
53 {0x84, BYTE_REG_OPER_OP_ORDER,
"test"},
54 {0x85, REG_OPER_OP_ORDER,
"test"},
55 {0x86, BYTE_REG_OPER_OP_ORDER,
"xchg"},
56 {0x87, REG_OPER_OP_ORDER,
"xchg"},
57 {0x88, BYTE_OPER_REG_OP_ORDER,
"mov"},
58 {0x89, OPER_REG_OP_ORDER,
"mov"},
59 {0x8A, BYTE_REG_OPER_OP_ORDER,
"mov"},
60 {0x8B, REG_OPER_OP_ORDER,
"mov"},
61 {0x8D, REG_OPER_OP_ORDER,
"lea"},
62 {-1, UNSET_OP_ORDER,
""}};
64#define ZERO_OPERAND_ENTRY(name, opcode) {opcode, UNSET_OP_ORDER, #name},
65static const ByteMnemonic zero_operands_instr[] = {
69static const ByteMnemonic call_jump_instr[] = {{0xE8, UNSET_OP_ORDER,
"call"},
70 {0xE9, UNSET_OP_ORDER,
"jmp"},
71 {-1, UNSET_OP_ORDER,
""}};
73#define SHORT_IMMEDIATE_ENTRY(name, code) {code * 8 + 5, UNSET_OP_ORDER, #name},
74static const ByteMnemonic short_immediate_instr[] = {
75 X86_ALU_CODES(SHORT_IMMEDIATE_ENTRY){-1, UNSET_OP_ORDER,
""}};
77static const char*
const conditional_code_suffix[] = {
78#define STRINGIFY(name, number) #name,
83#define STRINGIFY_NAME(name, code) #name,
84static const char*
const xmm_conditional_code_suffix[] = {
92 JUMP_CONDITIONAL_SHORT_INSTR,
101 ESCAPE_PREFIX = 0x0F,
102 OPERAND_SIZE_OVERRIDE_PREFIX = 0x66,
103 ADDRESS_SIZE_OVERRIDE_PREFIX = 0x67,
106 REPEQ_PREFIX = REP_PREFIX
116#define XMM_INSTRUCTION_ENTRY(name, code) \
117 {#name "ps", #name "pd", #name "ss", #name "sd"},
118static const XmmMnemonic xmm_instructions[] = {
121struct InstructionDesc {
123 InstructionType
type;
124 OperandType op_order_;
125 bool byte_size_operation;
128class InstructionTable :
public ValueObject {
131 const InstructionDesc&
Get(uint8_t
x)
const {
return instructions_[
x]; }
134 InstructionDesc instructions_[256];
137 void CopyTable(
const ByteMnemonic bm[], InstructionType
type);
138 void SetTableRange(InstructionType
type,
143 void AddJumpConditionalShort();
148InstructionTable::InstructionTable() {
153void InstructionTable::Clear() {
154 for (
int i = 0;
i < 256;
i++) {
155 instructions_[
i].mnem =
"(bad)";
156 instructions_[
i].type = NO_INSTR;
157 instructions_[
i].op_order_ = UNSET_OP_ORDER;
158 instructions_[
i].byte_size_operation =
false;
163 CopyTable(two_operands_instr, TWO_OPERANDS_INSTR);
164 CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR);
165 CopyTable(call_jump_instr, CALL_JUMP_INSTR);
166 CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR);
167 AddJumpConditionalShort();
168 SetTableRange(PUSHPOP_INSTR, 0x50, 0x57,
false,
"push");
169 SetTableRange(PUSHPOP_INSTR, 0x58, 0x5F,
false,
"pop");
170 SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF,
false,
"mov");
173void InstructionTable::CopyTable(
const ByteMnemonic bm[],
174 InstructionType
type) {
175 for (
int i = 0; bm[
i].b >= 0;
i++) {
176 InstructionDesc*
id = &instructions_[bm[
i].b];
177 id->mnem = bm[
i].mnem;
178 OperandType op_order = bm[
i].op_order_;
180 static_cast<OperandType
>(op_order & ~BYTE_SIZE_OPERAND_FLAG);
183 id->byte_size_operation = ((op_order & BYTE_SIZE_OPERAND_FLAG) != 0);
187void InstructionTable::SetTableRange(InstructionType
type,
192 for (uint8_t
b = start;
b <=
end;
b++) {
193 InstructionDesc*
id = &instructions_[
b];
197 id->byte_size_operation = byte_size;
201void InstructionTable::AddJumpConditionalShort() {
202 for (uint8_t
b = 0x70;
b <= 0x7F;
b++) {
203 InstructionDesc*
id = &instructions_[
b];
206 id->type = JUMP_CONDITIONAL_SHORT_INSTR;
210static InstructionTable instruction_table;
212static const InstructionDesc cmov_instructions[16] = {
213 {
"cmovo", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER,
false},
214 {
"cmovno", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER,
false},
215 {
"cmovc", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER,
false},
216 {
"cmovnc", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER,
false},
217 {
"cmovz", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER,
false},
218 {
"cmovnz", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER,
false},
219 {
"cmovna", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER,
false},
220 {
"cmova", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER,
false},
221 {
"cmovs", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER,
false},
222 {
"cmovns", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER,
false},
223 {
"cmovpe", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER,
false},
224 {
"cmovpo", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER,
false},
225 {
"cmovl", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER,
false},
226 {
"cmovge", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER,
false},
227 {
"cmovle", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER,
false},
228 {
"cmovg", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER,
false}};
233static constexpr int kMaxXmmRegisters = 16;
234static const char* xmm_regs[kMaxXmmRegisters] = {
235 "xmm0",
"xmm1",
"xmm2",
"xmm3",
"xmm4",
"xmm5",
"xmm6",
"xmm7",
236 "xmm8",
"xmm9",
"xmm10",
"xmm11",
"xmm12",
"xmm13",
"xmm14",
"xmm15"};
238class DisassemblerX64 :
public ValueObject {
247 byte_size_operand_(
false) {
248 buffer_[buffer_pos_] =
'\0';
251 virtual ~DisassemblerX64() {}
253 int InstructionDecode(
uword pc);
263 void setRex(uint8_t rex) {
264 ASSERT(0x40 == (rex & 0xF0));
268 bool rex() {
return rex_ != 0; }
270 bool rex_b() {
return (rex_ & 0x01) != 0; }
273 int base_reg(
int low_bits) {
return low_bits | ((rex_ & 0x01) << 3); }
275 bool rex_x() {
return (rex_ & 0x02) != 0; }
277 bool rex_r() {
return (rex_ & 0x04) != 0; }
279 bool rex_w() {
return (rex_ & 0x08) != 0; }
282 if (byte_size_operand_)
return BYTE_SIZE;
283 if (rex_w())
return QUADWORD_SIZE;
284 if (operand_size_ != 0)
return WORD_SIZE;
285 return DOUBLEWORD_SIZE;
288 const char* operand_size_code() {
289#if defined(TARGET_ARCH_X64)
290 return &
"b\0w\0l\0q\0"[2 * operand_size()];
293 return &
"b\0w\0\0\0q\0"[2 * operand_size()];
298 void get_modrm(uint8_t
data,
int* mod,
int* regop,
int* rm) {
299 *mod = (
data >> 6) & 3;
300 *regop = ((
data & 0x38) >> 3) | (rex_r() ? 8 : 0);
301 *rm = (
data & 7) | (rex_b() ? 8 : 0);
305 void get_sib(uint8_t
data,
int*
scale,
int* index,
int*
base) {
307 *index = ((
data >> 3) & 7) | (rex_x() ? 8 : 0);
308 *
base = (
data & 7) | (rex_b() ? 8 : 0);
312 const char* NameOfCPURegister(
int reg)
const {
316 const char* NameOfByteCPURegister(
int reg)
const {
317 return RegisterNames::RegisterByteName(
static_cast<ByteRegister>(reg));
321 const char* Rax()
const {
return NameOfCPURegister(0); }
323 const char* NameOfXMMRegister(
int reg)
const {
324 ASSERT((0 <= reg) && (reg < kMaxXmmRegisters));
325 return xmm_regs[reg];
329 void PrintJump(uint8_t* pc, int32_t disp);
330 void PrintAddress(uint8_t*
addr);
332 int PrintOperands(const
char* mnem, OperandType op_order, uint8_t*
data);
334 typedef const
char* (DisassemblerX64::* RegisterNameMapping)(
int reg) const;
336 int PrintRightOperandHelper(uint8_t* modrmp,
337 RegisterNameMapping register_name);
338 int PrintRightOperand(uint8_t* modrmp);
339 int PrintRightByteOperand(uint8_t* modrmp);
340 int PrintRightXMMOperand(uint8_t* modrmp);
341 void PrintDisp(
int disp, const
char* after);
343 void PrintImmediateValue(int64_t
value,
344 bool signed_value =
false,
345 int byte_count = -1);
346 int PrintImmediateOp(uint8_t*
data);
347 const
char* TwoByteMnemonic(uint8_t opcode);
348 int TwoByteOpcodeInstruction(uint8_t*
data);
349 int Print660F38Instruction(uint8_t*
data);
351 int F6F7Instruction(uint8_t*
data);
352 int ShiftInstruction(uint8_t*
data);
353 int JumpShort(uint8_t*
data);
354 int JumpConditional(uint8_t*
data);
355 int JumpConditionalShort(uint8_t*
data);
356 int SetCC(uint8_t*
data);
357 int FPUInstruction(uint8_t*
data);
358 int MemoryFPUInstruction(
int escape_opcode,
int regop, uint8_t* modrm_start);
359 int RegisterFPUInstruction(
int escape_opcode, uint8_t modrm_byte);
361 bool DecodeInstructionType(uint8_t**
data);
363 void UnimplementedInstruction(uint8_t
byte);
366 intptr_t buffer_size_;
367 intptr_t buffer_pos_;
371 uint8_t operand_size_;
373 uint8_t group_1_prefix_;
375 bool byte_size_operand_;
381void DisassemblerX64::Print(const
char*
format, ...) {
382 intptr_t available = buffer_size_ - buffer_pos_;
383 if (available <= 1) {
384 ASSERT(buffer_[buffer_pos_] ==
'\0');
387 char* buf = buffer_ + buffer_pos_;
393 (
length >= available) ? (buffer_size_ - 1) : (buffer_pos_ +
length);
394 ASSERT(buffer_pos_ < buffer_size_);
397int DisassemblerX64::PrintRightOperandHelper(
399 RegisterNameMapping direct_register_name) {
401 get_modrm(*modrmp, &mod, ®op, &rm);
402 RegisterNameMapping register_name =
403 (mod == 3) ? direct_register_name : &DisassemblerX64::NameOfCPURegister;
407#if defined(TARGET_ARCH_IA32)
409 Print(
"[0x%08x]",
abs);
411 int32_t disp =
LoadUnaligned(
reinterpret_cast<int32_t*
>(modrmp + 1));
413 PrintDisp(disp,
"]");
416 }
else if ((rm & 7) == 4) {
418 uint8_t sib = *(modrmp + 1);
421 if (index == 4 && (
base & 7) == 4 &&
scale == 0 ) {
424 Print(
"[%s]", NameOfCPURegister(
base));
426 }
else if (
base == 5) {
428 int32_t disp =
LoadUnaligned(
reinterpret_cast<int32_t*
>(modrmp + 2));
429 Print(
"[%s*%d", NameOfCPURegister(index), 1 <<
scale);
430 PrintDisp(disp,
"]");
432 }
else if (index != 4 &&
base != 5) {
434 Print(
"[%s+%s*%d]", NameOfCPURegister(
base), NameOfCPURegister(index),
438 UnimplementedInstruction(*modrmp);
442 Print(
"[%s]", NameOfCPURegister(rm));
450 uint8_t sib = *(modrmp + 1);
453 int disp = (mod == 2)
455 : *
reinterpret_cast<int8_t*
>(modrmp + 2);
456 if (index == 4 && (
base & 7) == 4 &&
scale == 0 ) {
457 Print(
"[%s", NameOfCPURegister(
base));
458 PrintDisp(disp,
"]");
460 Print(
"[%s+%s*%d", NameOfCPURegister(
base), NameOfCPURegister(index),
462 PrintDisp(disp,
"]");
464 return mod == 2 ? 6 : 3;
467 int disp = (mod == 2)
469 : *
reinterpret_cast<int8_t*
>(modrmp + 1);
470 Print(
"[%s", NameOfCPURegister(rm));
471 PrintDisp(disp,
"]");
472 return (mod == 2) ? 5 : 2;
476 Print(
"%s", (this->*register_name)(rm));
479 UnimplementedInstruction(*modrmp);
485int DisassemblerX64::PrintImmediate(uint8_t*
data,
493 value = *
reinterpret_cast<int8_t*
>(
data);
507 case DOUBLEWORD_SIZE:
525void DisassemblerX64::PrintImmediateValue(int64_t
value,
530 }
else if (signed_value && (
value < 0) && (
value >= -9)) {
533 if (byte_count == 1) {
534 int8_t v8 =
static_cast<int8_t
>(
value);
535 if (v8 < 0 && signed_value) {
536 Print(
"-%#" Px32, -
static_cast<uint8_t
>(v8));
538 Print(
"%#" Px32,
static_cast<uint8_t
>(v8));
540 }
else if (byte_count == 2) {
541 int16_t v16 =
static_cast<int16_t
>(
value);
542 if (v16 < 0 && signed_value) {
543 Print(
"-%#" Px32, -
static_cast<uint16_t
>(v16));
545 Print(
"%#" Px32,
static_cast<uint16_t
>(v16));
547 }
else if (byte_count == 4) {
548 int32_t v32 =
static_cast<int32_t
>(
value);
549 if (v32 < 0 && signed_value) {
550 Print(
"-%#010" Px32, -
static_cast<uint32_t
>(v32));
553 Print(
"%#010" Px32, v32);
555 Print(
"%#" Px32, v32);
558 }
else if (byte_count == 8) {
559 int64_t v64 =
static_cast<int64_t
>(
value);
560 if (v64 < 0 && signed_value) {
561 Print(
"-%#018" Px64, -
static_cast<uint64_t
>(v64));
563 if (v64 > 0xffffffffll) {
564 Print(
"%#018" Px64, v64);
566 Print(
"%#" Px64, v64);
571#if defined(TARGET_ARCH_X64)
572 if (
value < 0 && signed_value) {
578 int32_t v32 =
static_cast<int32_t
>(
value);
579 if (v32 < 0 && signed_value) {
580 Print(
"-%#" Px32, -v32);
582 Print(
"%#" Px32, v32);
589void DisassemblerX64::PrintDisp(
int disp,
const char* after) {
591 Print(
"-%#x", -disp);
595 if (after !=
nullptr) Print(
"%s", after);
600int DisassemblerX64::PrintImmediateOp(uint8_t*
data) {
601 bool byte_size_immediate = (*
data & 0x03) != 1;
602 uint8_t modrm = *(
data + 1);
604 get_modrm(modrm, &mod, ®op, &rm);
605 const char* mnem =
"Imm???";
632 UnimplementedInstruction(*
data);
635 Print(
"%s%s ", mnem, operand_size_code());
638 OperandSize immediate_size = byte_size_immediate ? BYTE_SIZE : operand_size();
640 PrintImmediate(
data + 1 +
count, immediate_size, byte_size_immediate);
645int DisassemblerX64::F6F7Instruction(uint8_t*
data) {
647 uint8_t modrm = *(
data + 1);
649 get_modrm(modrm, &mod, ®op, &rm);
650 static const char*
const mnemonics[] = {
"test",
nullptr,
"not",
"neg",
651 "mul",
"imul",
"div",
"idiv"};
652 const char* mnem = mnemonics[regop];
653 if (mod == 3 && regop != 0) {
657 Print(
"%s%s (%s,%s),%s", mnem, operand_size_code(), Rax(),
658 NameOfCPURegister(2), NameOfCPURegister(rm));
660 Print(
"%s%s %s", mnem, operand_size_code(), NameOfCPURegister(rm));
663 }
else if (regop == 0) {
664 Print(
"test%s ", operand_size_code());
669 }
else if (regop >= 4) {
670 Print(
"%s%s (%s,%s),", mnem, operand_size_code(), Rax(),
671 NameOfCPURegister(2));
672 return 1 + PrintRightOperand(
data + 1);
674 UnimplementedInstruction(*
data);
679int DisassemblerX64::ShiftInstruction(uint8_t*
data) {
683 uint8_t op = *
data & (~1);
684 if (op != 0xD0 && op != 0xD2 && op != 0xC0) {
685 UnimplementedInstruction(*
data);
688 uint8_t* modrm =
data + 1;
690 get_modrm(*modrm, &mod, ®op, &rm);
693 const char* mnem =
nullptr;
717 UnimplementedInstruction(*
data);
721 Print(
"%s%s ", mnem, operand_size_code());
722 if (byte_size_operand_) {
723 num_bytes += PrintRightByteOperand(modrm);
725 num_bytes += PrintRightOperand(modrm);
730 }
else if (op == 0xC0) {
731 uint8_t imm8 = *(
data + num_bytes);
741int DisassemblerX64::PrintRightOperand(uint8_t* modrmp) {
742 return PrintRightOperandHelper(modrmp, &DisassemblerX64::NameOfCPURegister);
745int DisassemblerX64::PrintRightByteOperand(uint8_t* modrmp) {
746 return PrintRightOperandHelper(modrmp,
747 &DisassemblerX64::NameOfByteCPURegister);
750int DisassemblerX64::PrintRightXMMOperand(uint8_t* modrmp) {
751 return PrintRightOperandHelper(modrmp, &DisassemblerX64::NameOfXMMRegister);
756int DisassemblerX64::PrintOperands(
const char* mnem,
757 OperandType op_order,
759 uint8_t modrm = *
data;
761 get_modrm(modrm, &mod, ®op, &rm);
763 const char* register_name = byte_size_operand_ ? NameOfByteCPURegister(regop)
764 : NameOfCPURegister(regop);
766 case REG_OPER_OP_ORDER: {
767 Print(
"%s%s %s,", mnem, operand_size_code(), register_name);
768 advance = byte_size_operand_ ? PrintRightByteOperand(
data)
769 : PrintRightOperand(
data);
772 case OPER_REG_OP_ORDER: {
773 Print(
"%s%s ", mnem, operand_size_code());
774 advance = byte_size_operand_ ? PrintRightByteOperand(
data)
775 : PrintRightOperand(
data);
776 Print(
",%s", register_name);
786void DisassemblerX64::PrintJump(uint8_t* pc, int32_t disp) {
787 if (FLAG_disassemble_relative) {
791 reinterpret_cast<uint8_t*
>(
reinterpret_cast<uintptr_t
>(pc) + disp));
795void DisassemblerX64::PrintAddress(uint8_t* addr_byte_ptr) {
796#if defined(TARGET_ARCH_X64)
797 Print(
"%#018" Px64 "",
reinterpret_cast<uint64_t
>(addr_byte_ptr));
799 Print(
"%#010" Px32 "",
reinterpret_cast<uint32_t
>(addr_byte_ptr));
805 if (name_of_stub !=
nullptr) {
806 Print(
" [stub: %s]", name_of_stub);
810int DisassemblerX64::JumpShort(uint8_t*
data) {
812 uint8_t
b = *(
data + 1);
813 int32_t disp =
static_cast<int8_t
>(
b) + 2;
815 PrintJump(
data, disp);
820int DisassemblerX64::JumpConditional(uint8_t*
data) {
822 uint8_t cond = *(
data + 1) & 0x0F;
824 const char* mnem = conditional_code_suffix[cond];
826 PrintJump(
data, disp);
831int DisassemblerX64::JumpConditionalShort(uint8_t*
data) {
832 uint8_t cond = *
data & 0x0F;
833 uint8_t
b = *(
data + 1);
834 int32_t disp =
static_cast<int8_t
>(
b) + 2;
835 const char* mnem = conditional_code_suffix[cond];
837 PrintJump(
data, disp);
842int DisassemblerX64::SetCC(uint8_t*
data) {
844 uint8_t cond = *(
data + 1) & 0x0F;
845 const char* mnem = conditional_code_suffix[cond];
846 Print(
"set%s ", mnem);
847 PrintRightByteOperand(
data + 2);
852int DisassemblerX64::FPUInstruction(uint8_t*
data) {
853 uint8_t escape_opcode = *
data;
854 ASSERT(0xD8 == (escape_opcode & 0xF8));
855 uint8_t modrm_byte = *(
data + 1);
857 if (modrm_byte >= 0xC0) {
858 return RegisterFPUInstruction(escape_opcode, modrm_byte);
860 return MemoryFPUInstruction(escape_opcode, modrm_byte,
data + 1);
864int DisassemblerX64::MemoryFPUInstruction(
int escape_opcode,
866 uint8_t* modrm_start) {
867 const char* mnem =
nullptr;
868 int regop = (modrm_byte >> 3) & 0x7;
869 switch (escape_opcode) {
926 if (mnem ==
nullptr) {
927 UnimplementedInstruction(escape_opcode);
931 int count = PrintRightOperand(modrm_start);
935int DisassemblerX64::RegisterFPUInstruction(
int escape_opcode,
936 uint8_t modrm_byte) {
937 bool has_register =
false;
938 const char* mnem =
"?";
940 switch (escape_opcode) {
942 UnimplementedInstruction(escape_opcode);
946 switch (modrm_byte & 0xF8) {
956 switch (modrm_byte) {
1012 UnimplementedInstruction(escape_opcode);
1019 if (modrm_byte == 0xE9) {
1022 UnimplementedInstruction(escape_opcode);
1028 if ((modrm_byte & 0xF8) == 0xE8) {
1030 has_register =
true;
1031 }
else if (modrm_byte == 0xE2) {
1034 UnimplementedInstruction(escape_opcode);
1040 has_register =
true;
1041 switch (modrm_byte & 0xF8) {
1055 UnimplementedInstruction(escape_opcode);
1061 has_register =
true;
1062 switch (modrm_byte & 0xF8) {
1070 UnimplementedInstruction(escape_opcode);
1076 if (modrm_byte == 0xD9) {
1079 has_register =
true;
1080 switch (modrm_byte & 0xF8) {
1094 UnimplementedInstruction(escape_opcode);
1101 if (modrm_byte == 0xE0) {
1103 }
else if ((modrm_byte & 0xF8) == 0xE8) {
1105 has_register =
true;
1110 UnimplementedInstruction(escape_opcode);
1115 Print(
"%s st%d", mnem, modrm_byte & 0x7);
1123bool DisassemblerX64::DecodeInstructionType(uint8_t**
data) {
1129 if (current == OPERAND_SIZE_OVERRIDE_PREFIX) {
1130 operand_size_ = current;
1131#if defined(TARGET_ARCH_X64)
1132 }
else if ((current & 0xF0) == 0x40) {
1138 }
else if ((current & 0xFE) == 0xF2) {
1139 group_1_prefix_ = current;
1140 }
else if (current == 0xF0) {
1148 const InstructionDesc& idesc = instruction_table.Get(current);
1149 byte_size_operand_ = idesc.byte_size_operation;
1151 switch (idesc.type) {
1152 case ZERO_OPERANDS_INSTR:
1153 if (current >= 0xA4 && current <= 0xA7) {
1155 if (group_1_prefix_ == REP_PREFIX) {
1159 if ((current & 0x01) == 0x01) {
1161 switch (operand_size()) {
1163 Print(
"%sw", idesc.mnem);
1165 case DOUBLEWORD_SIZE:
1166 Print(
"%sl", idesc.mnem);
1169 Print(
"%sq", idesc.mnem);
1176 Print(
"%s", idesc.mnem);
1178 }
else if (current == 0x99 && rex_w()) {
1181 Print(
"%s", idesc.mnem);
1186 case TWO_OPERANDS_INSTR:
1188 (*data) += PrintOperands(idesc.mnem, idesc.op_order_, *
data);
1191 case JUMP_CONDITIONAL_SHORT_INSTR:
1192 (*data) += JumpConditionalShort(*
data);
1195 case REGISTER_INSTR:
1196 Print(
"%s%s %s", idesc.mnem, operand_size_code(),
1197 NameOfCPURegister(base_reg(current & 0x07)));
1201 Print(
"%s %s", idesc.mnem, NameOfCPURegister(base_reg(current & 0x07)));
1204 case MOVE_REG_INSTR: {
1207 switch (operand_size()) {
1212 case DOUBLEWORD_SIZE:
1223 (*data) += 1 + imm_bytes;
1224 Print(
"mov%s %s,", operand_size_code(),
1225 NameOfCPURegister(base_reg(current & 0x07)));
1226 PrintImmediateValue(
addr,
false, imm_bytes);
1230 case CALL_JUMP_INSTR: {
1232 Print(
"%s ", idesc.mnem);
1233 PrintJump(*
data, disp);
1238 case SHORT_IMMEDIATE_INSTR: {
1239 Print(
"%s%s %s,", idesc.mnem, operand_size_code(), Rax());
1240 PrintImmediate(*
data + 1, DOUBLEWORD_SIZE);
1254int DisassemblerX64::Print660F38Instruction(uint8_t* current) {
1256 if (*current == 0x25) {
1257 get_modrm(*(current + 1), &mod, ®op, &rm);
1258 Print(
"pmovsxdq %s,", NameOfXMMRegister(regop));
1259 return 1 + PrintRightXMMOperand(current + 1);
1260 }
else if (*current == 0x29) {
1261 get_modrm(*(current + 1), &mod, ®op, &rm);
1262 Print(
"pcmpeqq %s,", NameOfXMMRegister(regop));
1263 return 1 + PrintRightXMMOperand(current + 1);
1265 UnimplementedInstruction(*current);
1273int DisassemblerX64::TwoByteOpcodeInstruction(uint8_t*
data) {
1274 uint8_t opcode = *(
data + 1);
1275 uint8_t* current =
data + 2;
1277 const char* mnemonic = TwoByteMnemonic(opcode);
1278 if (operand_size_ == 0x66) {
1281 if (opcode == 0xC6) {
1283 get_modrm(*current, &mod, ®op, &rm);
1284 Print(
"shufpd %s, ", NameOfXMMRegister(regop));
1285 current += PrintRightXMMOperand(current);
1286 Print(
" [%x]", *current);
1288 }
else if (opcode == 0x3A) {
1289 uint8_t third_byte = *current;
1291 if (third_byte == 0x16) {
1292 get_modrm(*current, &mod, ®op, &rm);
1294 current += PrintRightOperand(current);
1295 Print(
",%s,%d", NameOfXMMRegister(regop), (*current) & 7);
1297 }
else if (third_byte == 0x17) {
1298 get_modrm(*current, &mod, ®op, &rm);
1299 Print(
"extractps ");
1300 current += PrintRightOperand(current);
1301 Print(
", %s, %d", NameOfCPURegister(regop), (*current) & 3);
1303 }
else if (third_byte == 0x0b) {
1304 get_modrm(*current, &mod, ®op, &rm);
1306 Print(
"roundsd %s, ", NameOfCPURegister(regop));
1307 current += PrintRightOperand(current);
1308 Print(
", %d", (*current) & 3);
1311 UnimplementedInstruction(*
data);
1315 get_modrm(*current, &mod, ®op, &rm);
1316 if (opcode == 0x1f) {
1323 }
else if (mod == 2) {
1327 }
else if (opcode == 0x28) {
1328 Print(
"movapd %s, ", NameOfXMMRegister(regop));
1329 current += PrintRightXMMOperand(current);
1330 }
else if (opcode == 0x29) {
1332 current += PrintRightXMMOperand(current);
1333 Print(
", %s", NameOfXMMRegister(regop));
1334 }
else if (opcode == 0x38) {
1335 current += Print660F38Instruction(current);
1336 }
else if (opcode == 0x6E) {
1337 Print(
"mov%c %s,", rex_w() ?
'q' :
'd', NameOfXMMRegister(regop));
1338 current += PrintRightOperand(current);
1339 }
else if (opcode == 0x6F) {
1340 Print(
"movdqa %s,", NameOfXMMRegister(regop));
1341 current += PrintRightXMMOperand(current);
1342 }
else if (opcode == 0x7E) {
1343 Print(
"mov%c ", rex_w() ?
'q' :
'd');
1344 current += PrintRightOperand(current);
1345 Print(
",%s", NameOfXMMRegister(regop));
1346 }
else if (opcode == 0x7F) {
1348 current += PrintRightXMMOperand(current);
1349 Print(
",%s", NameOfXMMRegister(regop));
1350 }
else if (opcode == 0xD6) {
1352 current += PrintRightXMMOperand(current);
1353 Print(
",%s", NameOfXMMRegister(regop));
1354 }
else if (opcode == 0x50) {
1355 Print(
"movmskpd %s,", NameOfCPURegister(regop));
1356 current += PrintRightXMMOperand(current);
1357 }
else if (opcode == 0xD7) {
1358 Print(
"pmovmskb %s,", NameOfCPURegister(regop));
1359 current += PrintRightXMMOperand(current);
1361 const char* mnemonic =
"?";
1362 if (opcode == 0x5A) {
1363 mnemonic =
"cvtpd2ps";
1364 }
else if (0x51 <= opcode && opcode <= 0x5F) {
1365 mnemonic = xmm_instructions[opcode & 0xF].pd_name;
1366 }
else if (opcode == 0x14) {
1367 mnemonic =
"unpcklpd";
1368 }
else if (opcode == 0x15) {
1369 mnemonic =
"unpckhpd";
1370 }
else if (opcode == 0x2E) {
1371 mnemonic =
"ucomisd";
1372 }
else if (opcode == 0x2F) {
1373 mnemonic =
"comisd";
1374 }
else if (opcode == 0xFE) {
1376 }
else if (opcode == 0xFA) {
1378 }
else if (opcode == 0xEF) {
1381 UnimplementedInstruction(*
data);
1384 Print(
"%s %s,", mnemonic, NameOfXMMRegister(regop));
1385 current += PrintRightXMMOperand(current);
1388 }
else if (group_1_prefix_ == 0xF2) {
1391 if (opcode == 0x11 || opcode == 0x10) {
1395 get_modrm(*current, &mod, ®op, &rm);
1396 if (opcode == 0x11) {
1397 current += PrintRightXMMOperand(current);
1398 Print(
",%s", NameOfXMMRegister(regop));
1400 Print(
"%s,", NameOfXMMRegister(regop));
1401 current += PrintRightXMMOperand(current);
1403 }
else if (opcode == 0x2A) {
1406 get_modrm(*current, &mod, ®op, &rm);
1407 Print(
"%sd %s,", mnemonic, NameOfXMMRegister(regop));
1408 current += PrintRightOperand(current);
1409 }
else if (opcode == 0x2C) {
1413 get_modrm(*current, &mod, ®op, &rm);
1414 Print(
"cvttsd2si%s %s,", operand_size_code(), NameOfCPURegister(regop));
1415 current += PrintRightXMMOperand(current);
1416 }
else if (opcode == 0x2D) {
1419 get_modrm(*current, &mod, ®op, &rm);
1420 Print(
"cvtsd2si%s %s,", operand_size_code(), NameOfCPURegister(regop));
1421 current += PrintRightXMMOperand(current);
1422 }
else if (0x51 <= opcode && opcode <= 0x5F) {
1425 get_modrm(*current, &mod, ®op, &rm);
1426 const char* mnemonic =
1427 opcode == 0x5A ?
"cvtsd2ss" : xmm_instructions[opcode & 0xF].sd_name;
1428 Print(
"%s %s,", mnemonic, NameOfXMMRegister(regop));
1429 current += PrintRightXMMOperand(current);
1431 UnimplementedInstruction(*
data);
1434 }
else if (group_1_prefix_ == 0xF3) {
1436 if (opcode == 0x11 || opcode == 0x10) {
1440 get_modrm(*current, &mod, ®op, &rm);
1441 if (opcode == 0x11) {
1442 current += PrintRightOperand(current);
1443 Print(
",%s", NameOfXMMRegister(regop));
1445 Print(
"%s,", NameOfXMMRegister(regop));
1446 current += PrintRightOperand(current);
1448 }
else if (opcode == 0x2A) {
1451 get_modrm(*current, &mod, ®op, &rm);
1452 Print(
"%ss %s,", mnemonic, NameOfXMMRegister(regop));
1453 current += PrintRightOperand(current);
1454 }
else if (opcode == 0x2C || opcode == 0x2D) {
1455 bool truncating = (opcode & 1) == 0;
1459 get_modrm(*current, &mod, ®op, &rm);
1460 Print(
"cvt%sss2si%s %s,", truncating ?
"t" :
"", operand_size_code(),
1461 NameOfCPURegister(regop));
1462 current += PrintRightXMMOperand(current);
1463 }
else if (0x51 <= opcode && opcode <= 0x5F) {
1465 get_modrm(*current, &mod, ®op, &rm);
1466 const char* mnemonic =
1467 opcode == 0x5A ?
"cvtss2sd" : xmm_instructions[opcode & 0xF].ss_name;
1468 Print(
"%s %s,", mnemonic, NameOfXMMRegister(regop));
1469 current += PrintRightXMMOperand(current);
1470 }
else if (opcode == 0x7E) {
1472 get_modrm(*current, &mod, ®op, &rm);
1473 Print(
"movq %s, ", NameOfXMMRegister(regop));
1474 current += PrintRightXMMOperand(current);
1475 }
else if (opcode == 0xE6) {
1477 get_modrm(*current, &mod, ®op, &rm);
1478 Print(
"cvtdq2pd %s,", NameOfXMMRegister(regop));
1479 current += PrintRightXMMOperand(current);
1480 }
else if (opcode == 0xB8) {
1482 current += PrintOperands(mnemonic, REG_OPER_OP_ORDER, current);
1483 }
else if (opcode == 0xBD) {
1485 current += PrintOperands(
"lzcnt", REG_OPER_OP_ORDER, current);
1487 UnimplementedInstruction(*
data);
1490 }
else if (opcode == 0x1F) {
1493 get_modrm(*current, &mod, ®op, &rm);
1500 }
else if (mod == 2) {
1505 }
else if (opcode == 0x28 || opcode == 0x2f) {
1508 get_modrm(*current, &mod, ®op, &rm);
1509 const char* mnemonic = opcode == 0x28 ?
"movaps" :
"comiss";
1510 Print(
"%s %s,", mnemonic, NameOfXMMRegister(regop));
1511 current += PrintRightXMMOperand(current);
1512 }
else if (opcode == 0x29) {
1515 get_modrm(*current, &mod, ®op, &rm);
1517 current += PrintRightXMMOperand(current);
1518 Print(
",%s", NameOfXMMRegister(regop));
1519 }
else if (opcode == 0x11) {
1522 get_modrm(*current, &mod, ®op, &rm);
1524 current += PrintRightXMMOperand(current);
1525 Print(
",%s", NameOfXMMRegister(regop));
1526 }
else if (opcode == 0x50) {
1528 get_modrm(*current, &mod, ®op, &rm);
1529 Print(
"movmskps %s,", NameOfCPURegister(regop));
1530 current += PrintRightXMMOperand(current);
1531 }
else if (opcode == 0xA2 || opcode == 0x31) {
1533 Print(
"%s", mnemonic);
1534 }
else if ((opcode & 0xF0) == 0x40) {
1536 int condition = opcode & 0x0F;
1537 const InstructionDesc& idesc = cmov_instructions[condition];
1538 byte_size_operand_ = idesc.byte_size_operation;
1539 current += PrintOperands(idesc.mnem, idesc.op_order_, current);
1540 }
else if (0x10 <= opcode && opcode <= 0x16) {
1542 static const char*
const mnemonics[] = {
"movups",
nullptr,
"movhlps",
1543 nullptr,
"unpcklps",
"unpckhps",
1545 const char* mnemonic = mnemonics[opcode - 0x10];
1546 if (mnemonic ==
nullptr) {
1547 UnimplementedInstruction(*
data);
1551 get_modrm(*current, &mod, ®op, &rm);
1552 Print(
"%s %s,", mnemonic, NameOfXMMRegister(regop));
1553 current += PrintRightXMMOperand(current);
1554 }
else if (0x51 <= opcode && opcode <= 0x5F) {
1556 get_modrm(*current, &mod, ®op, &rm);
1557 const char* mnemonic =
1558 opcode == 0x5A ?
"cvtps2pd" : xmm_instructions[opcode & 0xF].ps_name;
1559 Print(
"%s %s,", mnemonic, NameOfXMMRegister(regop));
1560 current += PrintRightXMMOperand(current);
1561 }
else if (opcode == 0xC2 || opcode == 0xC6) {
1563 get_modrm(*current, &mod, ®op, &rm);
1564 if (opcode == 0xC2) {
1565 Print(
"cmpps %s,", NameOfXMMRegister(regop));
1566 current += PrintRightXMMOperand(current);
1567 Print(
" [%s]", xmm_conditional_code_suffix[*current]);
1570 Print(
"shufps %s,", NameOfXMMRegister(regop));
1571 current += PrintRightXMMOperand(current);
1572 Print(
" [%x]", *current);
1575 }
else if ((opcode & 0xF0) == 0x80) {
1577 current =
data + JumpConditional(
data);
1579 }
else if (opcode == 0xBE || opcode == 0xBF || opcode == 0xB6 ||
1580 opcode == 0xB7 || opcode == 0xAF || opcode == 0xB0 ||
1581 opcode == 0xB1 || opcode == 0xBC || opcode == 0xBD) {
1583 current += PrintOperands(mnemonic, REG_OPER_OP_ORDER, current);
1584 }
else if ((opcode & 0xF0) == 0x90) {
1587 }
else if (((opcode & 0xFE) == 0xA4) || ((opcode & 0xFE) == 0xAC) ||
1588 (opcode == 0xAB) || (opcode == 0xA3)) {
1590 Print(
"%s%s ", mnemonic, operand_size_code());
1592 get_modrm(*current, &mod, ®op, &rm);
1593 current += PrintRightOperand(current);
1594 Print(
",%s", NameOfCPURegister(regop));
1595 if ((opcode == 0xAB) || (opcode == 0xA3) || (opcode == 0xBD)) {
1597 }
else if ((opcode == 0xA5) || (opcode == 0xAD)) {
1601 current += PrintImmediate(current, BYTE_SIZE);
1603 }
else if (opcode == 0xBA && (*current & 0x60) == 0x60) {
1605 int r = (*current >> 3) & 7;
1606 static const char*
const names[4] = {
"bt",
"bts",
"btr",
"btc"};
1607 Print(
"%s ",
names[r - 4]);
1608 current += PrintRightOperand(current);
1609 uint8_t bit = *current++;
1612 UnimplementedInstruction(*
data);
1615 return static_cast<int>(current -
data);
1621const char* DisassemblerX64::TwoByteMnemonic(uint8_t opcode) {
1622 if (opcode == 0x5A) {
1624 }
else if (0x51 <= opcode && opcode <= 0x5F) {
1625 return xmm_instructions[opcode & 0xF].ps_name;
1627 if (0xA2 <= opcode && opcode <= 0xBF) {
1628 static const char*
const mnemonics[] = {
1629 "cpuid",
"bt",
"shld",
"shld",
nullptr,
nullptr,
1630 nullptr,
nullptr,
nullptr,
"bts",
"shrd",
"shrd",
1631 nullptr,
"imul",
"cmpxchg",
"cmpxchg",
nullptr,
nullptr,
1632 nullptr,
nullptr,
"movzxb",
"movzxw",
"popcnt",
nullptr,
1633 nullptr,
nullptr,
"bsf",
"bsr",
"movsxb",
"movsxw"};
1634 return mnemonics[opcode - 0xA2];
1652int DisassemblerX64::InstructionDecode(
uword pc) {
1653 uint8_t*
data =
reinterpret_cast<uint8_t*
>(pc);
1655 const bool processed = DecodeInstructionType(&
data);
1661 PrintImmediateValue(*
reinterpret_cast<uint16_t*
>(
data + 1));
1666 Print(
"enter %d, %d", *
reinterpret_cast<uint16_t*
>(
data + 1),
data[3]);
1674 get_modrm(*(
data + 1), &mod, ®op, &rm);
1675 int32_t imm = *
data == 0x6B
1678 Print(
"imul%s %s,%s,", operand_size_code(), NameOfCPURegister(regop),
1679 NameOfCPURegister(rm));
1680 PrintImmediateValue(imm);
1681 data += 2 + (*
data == 0x6B ? 1 : 4);
1692 data += TwoByteOpcodeInstruction(
data);
1698 get_modrm(*
data, &mod, ®op, &rm);
1708 get_modrm(*
data, &mod, ®op, &rm);
1709 const char* mnem =
nullptr;
1730 Print(
"%s%s ", mnem, operand_size_code());
1740 bool is_byte = *
data == 0xC6;
1744 data += PrintRightByteOperand(
data);
1746 data += PrintImmediate(
data, BYTE_SIZE);
1748 Print(
"mov%s ", operand_size_code());
1752 PrintImmediate(
data, operand_size(),
true);
1757 byte_size_operand_ =
true;
1764 bool is_byte = *
data == 0x88;
1767 get_modrm(*
data, &mod, ®op, &rm);
1770 data += PrintRightByteOperand(
data);
1771 Print(
",%s", NameOfByteCPURegister(regop));
1773 Print(
"mov%s ", operand_size_code());
1775 Print(
",%s", NameOfCPURegister(regop));
1787 int reg = (*
data & 0x7) | (rex_b() ? 8 : 0);
1791 Print(
"xchg%s %s, %s", operand_size_code(), Rax(),
1792 NameOfCPURegister(reg));
1813 uint8_t opcode = *
data;
1815 const bool is_not_8bit = opcode >= 0xB8;
1816 int reg = (opcode & 0x7) | (rex_b() ? 8 : 0);
1818 Print(
"mov%s %s,", operand_size_code(), NameOfCPURegister(reg));
1820 PrintImmediate(
data, operand_size(),
false);
1822 Print(
"movb %s,", NameOfByteCPURegister(reg));
1823 data += PrintImmediate(
data, BYTE_SIZE,
false);
1830 get_modrm(*
data, &mod, ®op, &rm);
1833 data += PrintRightByteOperand(
data);
1835 UnimplementedInstruction(*
data);
1842 PrintImmediateValue(
1849 PrintImmediateValue(*
reinterpret_cast<int8_t*
>(
data + 1));
1856 switch (operand_size()) {
1857 case DOUBLEWORD_SIZE: {
1858 PrintAddress(
reinterpret_cast<uint8_t*
>(
1859 *
reinterpret_cast<int32_t*
>(
data + 1)));
1860 if (*
data == 0xA1) {
1861 Print(
"movzxlq %s,(", Rax());
1862 PrintAddress(
reinterpret_cast<uint8_t*
>(
1863 *
reinterpret_cast<int32_t*
>(
data + 1)));
1867 PrintAddress(
reinterpret_cast<uint8_t*
>(
1868 *
reinterpret_cast<int32_t*
>(
data + 1)));
1869 Print(
"),%s", Rax());
1874 case QUADWORD_SIZE: {
1876 if (*
data == 0xA1) {
1877 Print(
"movq %s,(", Rax());
1878 PrintAddress(*
reinterpret_cast<uint8_t**
>(
data + 1));
1882 PrintAddress(*
reinterpret_cast<uint8_t**
>(
data + 1));
1883 Print(
"),%s", Rax());
1889 UnimplementedInstruction(*
data);
1896 PrintImmediateValue(*
reinterpret_cast<uint8_t*
>(
data + 1));
1902 Print(
"test%s %s,", operand_size_code(), Rax());
1903 data += PrintImmediate(
data, operand_size());
1918 byte_size_operand_ =
true;
1943 byte_size_operand_ =
true;
1959 Print(
"inc %s", NameOfCPURegister(*
data & 7));
1971 Print(
"dec %s", NameOfCPURegister(*
data & 7));
1975#if defined(TARGET_ARCH_IA32)
1986 UnimplementedInstruction(*
data);
1991 ASSERT(buffer_[buffer_pos_] ==
'\0');
1993 int instr_len =
data -
reinterpret_cast<uint8_t*
>(pc);
1999void DisassemblerX64::UnimplementedInstruction(uint8_t
byte) {
2006 intptr_t human_size,
2013 DisassemblerX64 decoder(human_buffer, human_size);
2014 int instruction_length = decoder.InstructionDecode(pc);
2015 uint8_t* pc_ptr =
reinterpret_cast<uint8_t*
>(pc);
2017 int remaining_size = hex_size - hex_index;
2018 for (
int i = 0; (
i < instruction_length) && (remaining_size > 2); ++
i) {
2019 Utils::SNPrint(&hex_buffer[hex_index], remaining_size,
"%02x", pc_ptr[
i]);
2021 remaining_size -= 2;
2023 hex_buffer[hex_index] =
'\0';
2024 if (out_instr_len !=
nullptr) {
2025 *out_instr_len = instruction_length;
2029#if defined(TARGET_ARCH_X64)
2030 if (!
code.IsNull()) {
2037 if (!
code.IsNull() &&
code.is_alive()) {
2038 intptr_t offsets_length =
code.pointer_offsets_length();
2039 for (intptr_t
i = 0;
i < offsets_length;
i++) {
2041 if ((pc <=
addr) && (
addr < (pc + instruction_length))) {
static uint32_t buffer_size(uint32_t offset, uint32_t maxAlignment)
static void DecodeInstruction(char *hex_buffer, intptr_t hex_size, char *human_buffer, intptr_t human_size, int *out_instr_len, const Code &code, Object **object, uword pc)
static const char * RegisterName(Register reg)
static const char * NameOfStub(uword entry_point)
static int SNPrint(char *str, size_t size, const char *format,...) PRINTF_ATTRIBUTE(3
static int static int VSNPrint(char *str, size_t size, const char *format, va_list args)
#define X86_CONDITIONAL_SUFFIXES(F)
#define XMM_CONDITIONAL_CODES(F)
#define X86_ZERO_OPERAND_1_BYTE_INSTRUCTIONS(F)
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
uint32_t uint32_t * format
const GrXPFactory * Get(SkBlendMode mode)
static const char *const names[]
intx_t sign_extend(int32_t x)
bool DecodeLoadObjectFromPoolOrThread(uword pc, const Code &code, Object *obj)
static T LoadUnaligned(const T *ptr)
static int8_t data[kExtLength]
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
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
SIN Vec< N, float > abs(const Vec< N, float > &x)