V8 Project
disasm-arm64.cc
Go to the documentation of this file.
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 #include <assert.h>
6 #include <stdarg.h>
7 #include <stdio.h>
8 #include <string.h>
9 
10 #include "src/v8.h"
11 
12 #if V8_TARGET_ARCH_ARM64
13 
15 #include "src/arm64/disasm-arm64.h"
17 #include "src/disasm.h"
18 #include "src/macro-assembler.h"
19 
20 namespace v8 {
21 namespace internal {
22 
23 
25  buffer_size_ = 256;
26  buffer_ = reinterpret_cast<char*>(malloc(buffer_size_));
27  buffer_pos_ = 0;
28  own_buffer_ = true;
29 }
30 
31 
32 Disassembler::Disassembler(char* text_buffer, int buffer_size) {
33  buffer_size_ = buffer_size;
34  buffer_ = text_buffer;
35  buffer_pos_ = 0;
36  own_buffer_ = false;
37 }
38 
39 
41  if (own_buffer_) {
42  free(buffer_);
43  }
44 }
45 
46 
48  return buffer_;
49 }
50 
51 
52 void Disassembler::VisitAddSubImmediate(Instruction* instr) {
53  bool rd_is_zr = RdIsZROrSP(instr);
54  bool stack_op = (rd_is_zr || RnIsZROrSP(instr)) &&
55  (instr->ImmAddSub() == 0) ? true : false;
56  const char *mnemonic = "";
57  const char *form = "'Rds, 'Rns, 'IAddSub";
58  const char *form_cmp = "'Rns, 'IAddSub";
59  const char *form_mov = "'Rds, 'Rns";
60 
61  switch (instr->Mask(AddSubImmediateMask)) {
62  case ADD_w_imm:
63  case ADD_x_imm: {
64  mnemonic = "add";
65  if (stack_op) {
66  mnemonic = "mov";
67  form = form_mov;
68  }
69  break;
70  }
71  case ADDS_w_imm:
72  case ADDS_x_imm: {
73  mnemonic = "adds";
74  if (rd_is_zr) {
75  mnemonic = "cmn";
76  form = form_cmp;
77  }
78  break;
79  }
80  case SUB_w_imm:
81  case SUB_x_imm: mnemonic = "sub"; break;
82  case SUBS_w_imm:
83  case SUBS_x_imm: {
84  mnemonic = "subs";
85  if (rd_is_zr) {
86  mnemonic = "cmp";
87  form = form_cmp;
88  }
89  break;
90  }
91  default: UNREACHABLE();
92  }
93  Format(instr, mnemonic, form);
94 }
95 
96 
97 void Disassembler::VisitAddSubShifted(Instruction* instr) {
98  bool rd_is_zr = RdIsZROrSP(instr);
99  bool rn_is_zr = RnIsZROrSP(instr);
100  const char *mnemonic = "";
101  const char *form = "'Rd, 'Rn, 'Rm'HDP";
102  const char *form_cmp = "'Rn, 'Rm'HDP";
103  const char *form_neg = "'Rd, 'Rm'HDP";
104 
105  switch (instr->Mask(AddSubShiftedMask)) {
106  case ADD_w_shift:
107  case ADD_x_shift: mnemonic = "add"; break;
108  case ADDS_w_shift:
109  case ADDS_x_shift: {
110  mnemonic = "adds";
111  if (rd_is_zr) {
112  mnemonic = "cmn";
113  form = form_cmp;
114  }
115  break;
116  }
117  case SUB_w_shift:
118  case SUB_x_shift: {
119  mnemonic = "sub";
120  if (rn_is_zr) {
121  mnemonic = "neg";
122  form = form_neg;
123  }
124  break;
125  }
126  case SUBS_w_shift:
127  case SUBS_x_shift: {
128  mnemonic = "subs";
129  if (rd_is_zr) {
130  mnemonic = "cmp";
131  form = form_cmp;
132  } else if (rn_is_zr) {
133  mnemonic = "negs";
134  form = form_neg;
135  }
136  break;
137  }
138  default: UNREACHABLE();
139  }
140  Format(instr, mnemonic, form);
141 }
142 
143 
144 void Disassembler::VisitAddSubExtended(Instruction* instr) {
145  bool rd_is_zr = RdIsZROrSP(instr);
146  const char *mnemonic = "";
147  Extend mode = static_cast<Extend>(instr->ExtendMode());
148  const char *form = ((mode == UXTX) || (mode == SXTX)) ?
149  "'Rds, 'Rns, 'Xm'Ext" : "'Rds, 'Rns, 'Wm'Ext";
150  const char *form_cmp = ((mode == UXTX) || (mode == SXTX)) ?
151  "'Rns, 'Xm'Ext" : "'Rns, 'Wm'Ext";
152 
153  switch (instr->Mask(AddSubExtendedMask)) {
154  case ADD_w_ext:
155  case ADD_x_ext: mnemonic = "add"; break;
156  case ADDS_w_ext:
157  case ADDS_x_ext: {
158  mnemonic = "adds";
159  if (rd_is_zr) {
160  mnemonic = "cmn";
161  form = form_cmp;
162  }
163  break;
164  }
165  case SUB_w_ext:
166  case SUB_x_ext: mnemonic = "sub"; break;
167  case SUBS_w_ext:
168  case SUBS_x_ext: {
169  mnemonic = "subs";
170  if (rd_is_zr) {
171  mnemonic = "cmp";
172  form = form_cmp;
173  }
174  break;
175  }
176  default: UNREACHABLE();
177  }
178  Format(instr, mnemonic, form);
179 }
180 
181 
182 void Disassembler::VisitAddSubWithCarry(Instruction* instr) {
183  bool rn_is_zr = RnIsZROrSP(instr);
184  const char *mnemonic = "";
185  const char *form = "'Rd, 'Rn, 'Rm";
186  const char *form_neg = "'Rd, 'Rm";
187 
188  switch (instr->Mask(AddSubWithCarryMask)) {
189  case ADC_w:
190  case ADC_x: mnemonic = "adc"; break;
191  case ADCS_w:
192  case ADCS_x: mnemonic = "adcs"; break;
193  case SBC_w:
194  case SBC_x: {
195  mnemonic = "sbc";
196  if (rn_is_zr) {
197  mnemonic = "ngc";
198  form = form_neg;
199  }
200  break;
201  }
202  case SBCS_w:
203  case SBCS_x: {
204  mnemonic = "sbcs";
205  if (rn_is_zr) {
206  mnemonic = "ngcs";
207  form = form_neg;
208  }
209  break;
210  }
211  default: UNREACHABLE();
212  }
213  Format(instr, mnemonic, form);
214 }
215 
216 
217 void Disassembler::VisitLogicalImmediate(Instruction* instr) {
218  bool rd_is_zr = RdIsZROrSP(instr);
219  bool rn_is_zr = RnIsZROrSP(instr);
220  const char *mnemonic = "";
221  const char *form = "'Rds, 'Rn, 'ITri";
222 
223  if (instr->ImmLogical() == 0) {
224  // The immediate encoded in the instruction is not in the expected format.
225  Format(instr, "unallocated", "(LogicalImmediate)");
226  return;
227  }
228 
229  switch (instr->Mask(LogicalImmediateMask)) {
230  case AND_w_imm:
231  case AND_x_imm: mnemonic = "and"; break;
232  case ORR_w_imm:
233  case ORR_x_imm: {
234  mnemonic = "orr";
235  unsigned reg_size = (instr->SixtyFourBits() == 1) ? kXRegSizeInBits
236  : kWRegSizeInBits;
237  if (rn_is_zr && !IsMovzMovnImm(reg_size, instr->ImmLogical())) {
238  mnemonic = "mov";
239  form = "'Rds, 'ITri";
240  }
241  break;
242  }
243  case EOR_w_imm:
244  case EOR_x_imm: mnemonic = "eor"; break;
245  case ANDS_w_imm:
246  case ANDS_x_imm: {
247  mnemonic = "ands";
248  if (rd_is_zr) {
249  mnemonic = "tst";
250  form = "'Rn, 'ITri";
251  }
252  break;
253  }
254  default: UNREACHABLE();
255  }
256  Format(instr, mnemonic, form);
257 }
258 
259 
260 bool Disassembler::IsMovzMovnImm(unsigned reg_size, uint64_t value) {
261  DCHECK((reg_size == kXRegSizeInBits) ||
262  ((reg_size == kWRegSizeInBits) && (value <= 0xffffffff)));
263 
264  // Test for movz: 16-bits set at positions 0, 16, 32 or 48.
265  if (((value & 0xffffffffffff0000UL) == 0UL) ||
266  ((value & 0xffffffff0000ffffUL) == 0UL) ||
267  ((value & 0xffff0000ffffffffUL) == 0UL) ||
268  ((value & 0x0000ffffffffffffUL) == 0UL)) {
269  return true;
270  }
271 
272  // Test for movn: NOT(16-bits set at positions 0, 16, 32 or 48).
273  if ((reg_size == kXRegSizeInBits) &&
274  (((value & 0xffffffffffff0000UL) == 0xffffffffffff0000UL) ||
275  ((value & 0xffffffff0000ffffUL) == 0xffffffff0000ffffUL) ||
276  ((value & 0xffff0000ffffffffUL) == 0xffff0000ffffffffUL) ||
277  ((value & 0x0000ffffffffffffUL) == 0x0000ffffffffffffUL))) {
278  return true;
279  }
280  if ((reg_size == kWRegSizeInBits) &&
281  (((value & 0xffff0000) == 0xffff0000) ||
282  ((value & 0x0000ffff) == 0x0000ffff))) {
283  return true;
284  }
285  return false;
286 }
287 
288 
289 void Disassembler::VisitLogicalShifted(Instruction* instr) {
290  bool rd_is_zr = RdIsZROrSP(instr);
291  bool rn_is_zr = RnIsZROrSP(instr);
292  const char *mnemonic = "";
293  const char *form = "'Rd, 'Rn, 'Rm'HLo";
294 
295  switch (instr->Mask(LogicalShiftedMask)) {
296  case AND_w:
297  case AND_x: mnemonic = "and"; break;
298  case BIC_w:
299  case BIC_x: mnemonic = "bic"; break;
300  case EOR_w:
301  case EOR_x: mnemonic = "eor"; break;
302  case EON_w:
303  case EON_x: mnemonic = "eon"; break;
304  case BICS_w:
305  case BICS_x: mnemonic = "bics"; break;
306  case ANDS_w:
307  case ANDS_x: {
308  mnemonic = "ands";
309  if (rd_is_zr) {
310  mnemonic = "tst";
311  form = "'Rn, 'Rm'HLo";
312  }
313  break;
314  }
315  case ORR_w:
316  case ORR_x: {
317  mnemonic = "orr";
318  if (rn_is_zr && (instr->ImmDPShift() == 0) && (instr->ShiftDP() == LSL)) {
319  mnemonic = "mov";
320  form = "'Rd, 'Rm";
321  }
322  break;
323  }
324  case ORN_w:
325  case ORN_x: {
326  mnemonic = "orn";
327  if (rn_is_zr) {
328  mnemonic = "mvn";
329  form = "'Rd, 'Rm'HLo";
330  }
331  break;
332  }
333  default: UNREACHABLE();
334  }
335 
336  Format(instr, mnemonic, form);
337 }
338 
339 
340 void Disassembler::VisitConditionalCompareRegister(Instruction* instr) {
341  const char *mnemonic = "";
342  const char *form = "'Rn, 'Rm, 'INzcv, 'Cond";
343 
344  switch (instr->Mask(ConditionalCompareRegisterMask)) {
345  case CCMN_w:
346  case CCMN_x: mnemonic = "ccmn"; break;
347  case CCMP_w:
348  case CCMP_x: mnemonic = "ccmp"; break;
349  default: UNREACHABLE();
350  }
351  Format(instr, mnemonic, form);
352 }
353 
354 
355 void Disassembler::VisitConditionalCompareImmediate(Instruction* instr) {
356  const char *mnemonic = "";
357  const char *form = "'Rn, 'IP, 'INzcv, 'Cond";
358 
359  switch (instr->Mask(ConditionalCompareImmediateMask)) {
360  case CCMN_w_imm:
361  case CCMN_x_imm: mnemonic = "ccmn"; break;
362  case CCMP_w_imm:
363  case CCMP_x_imm: mnemonic = "ccmp"; break;
364  default: UNREACHABLE();
365  }
366  Format(instr, mnemonic, form);
367 }
368 
369 
370 void Disassembler::VisitConditionalSelect(Instruction* instr) {
371  bool rnm_is_zr = (RnIsZROrSP(instr) && RmIsZROrSP(instr));
372  bool rn_is_rm = (instr->Rn() == instr->Rm());
373  const char *mnemonic = "";
374  const char *form = "'Rd, 'Rn, 'Rm, 'Cond";
375  const char *form_test = "'Rd, 'CInv";
376  const char *form_update = "'Rd, 'Rn, 'CInv";
377 
378  Condition cond = static_cast<Condition>(instr->Condition());
379  bool invertible_cond = (cond != al) && (cond != nv);
380 
381  switch (instr->Mask(ConditionalSelectMask)) {
382  case CSEL_w:
383  case CSEL_x: mnemonic = "csel"; break;
384  case CSINC_w:
385  case CSINC_x: {
386  mnemonic = "csinc";
387  if (rnm_is_zr && invertible_cond) {
388  mnemonic = "cset";
389  form = form_test;
390  } else if (rn_is_rm && invertible_cond) {
391  mnemonic = "cinc";
392  form = form_update;
393  }
394  break;
395  }
396  case CSINV_w:
397  case CSINV_x: {
398  mnemonic = "csinv";
399  if (rnm_is_zr && invertible_cond) {
400  mnemonic = "csetm";
401  form = form_test;
402  } else if (rn_is_rm && invertible_cond) {
403  mnemonic = "cinv";
404  form = form_update;
405  }
406  break;
407  }
408  case CSNEG_w:
409  case CSNEG_x: {
410  mnemonic = "csneg";
411  if (rn_is_rm && invertible_cond) {
412  mnemonic = "cneg";
413  form = form_update;
414  }
415  break;
416  }
417  default: UNREACHABLE();
418  }
419  Format(instr, mnemonic, form);
420 }
421 
422 
423 void Disassembler::VisitBitfield(Instruction* instr) {
424  unsigned s = instr->ImmS();
425  unsigned r = instr->ImmR();
426  unsigned rd_size_minus_1 =
427  ((instr->SixtyFourBits() == 1) ? kXRegSizeInBits : kWRegSizeInBits) - 1;
428  const char *mnemonic = "";
429  const char *form = "";
430  const char *form_shift_right = "'Rd, 'Rn, 'IBr";
431  const char *form_extend = "'Rd, 'Wn";
432  const char *form_bfiz = "'Rd, 'Rn, 'IBZ-r, 'IBs+1";
433  const char *form_bfx = "'Rd, 'Rn, 'IBr, 'IBs-r+1";
434  const char *form_lsl = "'Rd, 'Rn, 'IBZ-r";
435 
436  switch (instr->Mask(BitfieldMask)) {
437  case SBFM_w:
438  case SBFM_x: {
439  mnemonic = "sbfx";
440  form = form_bfx;
441  if (r == 0) {
442  form = form_extend;
443  if (s == 7) {
444  mnemonic = "sxtb";
445  } else if (s == 15) {
446  mnemonic = "sxth";
447  } else if ((s == 31) && (instr->SixtyFourBits() == 1)) {
448  mnemonic = "sxtw";
449  } else {
450  form = form_bfx;
451  }
452  } else if (s == rd_size_minus_1) {
453  mnemonic = "asr";
454  form = form_shift_right;
455  } else if (s < r) {
456  mnemonic = "sbfiz";
457  form = form_bfiz;
458  }
459  break;
460  }
461  case UBFM_w:
462  case UBFM_x: {
463  mnemonic = "ubfx";
464  form = form_bfx;
465  if (r == 0) {
466  form = form_extend;
467  if (s == 7) {
468  mnemonic = "uxtb";
469  } else if (s == 15) {
470  mnemonic = "uxth";
471  } else {
472  form = form_bfx;
473  }
474  }
475  if (s == rd_size_minus_1) {
476  mnemonic = "lsr";
477  form = form_shift_right;
478  } else if (r == s + 1) {
479  mnemonic = "lsl";
480  form = form_lsl;
481  } else if (s < r) {
482  mnemonic = "ubfiz";
483  form = form_bfiz;
484  }
485  break;
486  }
487  case BFM_w:
488  case BFM_x: {
489  mnemonic = "bfxil";
490  form = form_bfx;
491  if (s < r) {
492  mnemonic = "bfi";
493  form = form_bfiz;
494  }
495  }
496  }
497  Format(instr, mnemonic, form);
498 }
499 
500 
501 void Disassembler::VisitExtract(Instruction* instr) {
502  const char *mnemonic = "";
503  const char *form = "'Rd, 'Rn, 'Rm, 'IExtract";
504 
505  switch (instr->Mask(ExtractMask)) {
506  case EXTR_w:
507  case EXTR_x: {
508  if (instr->Rn() == instr->Rm()) {
509  mnemonic = "ror";
510  form = "'Rd, 'Rn, 'IExtract";
511  } else {
512  mnemonic = "extr";
513  }
514  break;
515  }
516  default: UNREACHABLE();
517  }
518  Format(instr, mnemonic, form);
519 }
520 
521 
522 void Disassembler::VisitPCRelAddressing(Instruction* instr) {
523  switch (instr->Mask(PCRelAddressingMask)) {
524  case ADR: Format(instr, "adr", "'Xd, 'AddrPCRelByte"); break;
525  // ADRP is not implemented.
526  default: Format(instr, "unimplemented", "(PCRelAddressing)");
527  }
528 }
529 
530 
531 void Disassembler::VisitConditionalBranch(Instruction* instr) {
532  switch (instr->Mask(ConditionalBranchMask)) {
533  case B_cond: Format(instr, "b.'CBrn", "'BImmCond"); break;
534  default: UNREACHABLE();
535  }
536 }
537 
538 
539 void Disassembler::VisitUnconditionalBranchToRegister(Instruction* instr) {
540  const char *mnemonic = "unimplemented";
541  const char *form = "'Xn";
542 
543  switch (instr->Mask(UnconditionalBranchToRegisterMask)) {
544  case BR: mnemonic = "br"; break;
545  case BLR: mnemonic = "blr"; break;
546  case RET: {
547  mnemonic = "ret";
548  if (instr->Rn() == kLinkRegCode) {
549  form = NULL;
550  }
551  break;
552  }
553  default: form = "(UnconditionalBranchToRegister)";
554  }
555  Format(instr, mnemonic, form);
556 }
557 
558 
559 void Disassembler::VisitUnconditionalBranch(Instruction* instr) {
560  const char *mnemonic = "";
561  const char *form = "'BImmUncn";
562 
563  switch (instr->Mask(UnconditionalBranchMask)) {
564  case B: mnemonic = "b"; break;
565  case BL: mnemonic = "bl"; break;
566  default: UNREACHABLE();
567  }
568  Format(instr, mnemonic, form);
569 }
570 
571 
572 void Disassembler::VisitDataProcessing1Source(Instruction* instr) {
573  const char *mnemonic = "";
574  const char *form = "'Rd, 'Rn";
575 
576  switch (instr->Mask(DataProcessing1SourceMask)) {
577  #define FORMAT(A, B) \
578  case A##_w: \
579  case A##_x: mnemonic = B; break;
580  FORMAT(RBIT, "rbit");
581  FORMAT(REV16, "rev16");
582  FORMAT(REV, "rev");
583  FORMAT(CLZ, "clz");
584  FORMAT(CLS, "cls");
585  #undef FORMAT
586  case REV32_x: mnemonic = "rev32"; break;
587  default: UNREACHABLE();
588  }
589  Format(instr, mnemonic, form);
590 }
591 
592 
593 void Disassembler::VisitDataProcessing2Source(Instruction* instr) {
594  const char *mnemonic = "unimplemented";
595  const char *form = "'Rd, 'Rn, 'Rm";
596 
597  switch (instr->Mask(DataProcessing2SourceMask)) {
598  #define FORMAT(A, B) \
599  case A##_w: \
600  case A##_x: mnemonic = B; break;
601  FORMAT(UDIV, "udiv");
602  FORMAT(SDIV, "sdiv");
603  FORMAT(LSLV, "lsl");
604  FORMAT(LSRV, "lsr");
605  FORMAT(ASRV, "asr");
606  FORMAT(RORV, "ror");
607  #undef FORMAT
608  default: form = "(DataProcessing2Source)";
609  }
610  Format(instr, mnemonic, form);
611 }
612 
613 
614 void Disassembler::VisitDataProcessing3Source(Instruction* instr) {
615  bool ra_is_zr = RaIsZROrSP(instr);
616  const char *mnemonic = "";
617  const char *form = "'Xd, 'Wn, 'Wm, 'Xa";
618  const char *form_rrr = "'Rd, 'Rn, 'Rm";
619  const char *form_rrrr = "'Rd, 'Rn, 'Rm, 'Ra";
620  const char *form_xww = "'Xd, 'Wn, 'Wm";
621  const char *form_xxx = "'Xd, 'Xn, 'Xm";
622 
623  switch (instr->Mask(DataProcessing3SourceMask)) {
624  case MADD_w:
625  case MADD_x: {
626  mnemonic = "madd";
627  form = form_rrrr;
628  if (ra_is_zr) {
629  mnemonic = "mul";
630  form = form_rrr;
631  }
632  break;
633  }
634  case MSUB_w:
635  case MSUB_x: {
636  mnemonic = "msub";
637  form = form_rrrr;
638  if (ra_is_zr) {
639  mnemonic = "mneg";
640  form = form_rrr;
641  }
642  break;
643  }
644  case SMADDL_x: {
645  mnemonic = "smaddl";
646  if (ra_is_zr) {
647  mnemonic = "smull";
648  form = form_xww;
649  }
650  break;
651  }
652  case SMSUBL_x: {
653  mnemonic = "smsubl";
654  if (ra_is_zr) {
655  mnemonic = "smnegl";
656  form = form_xww;
657  }
658  break;
659  }
660  case UMADDL_x: {
661  mnemonic = "umaddl";
662  if (ra_is_zr) {
663  mnemonic = "umull";
664  form = form_xww;
665  }
666  break;
667  }
668  case UMSUBL_x: {
669  mnemonic = "umsubl";
670  if (ra_is_zr) {
671  mnemonic = "umnegl";
672  form = form_xww;
673  }
674  break;
675  }
676  case SMULH_x: {
677  mnemonic = "smulh";
678  form = form_xxx;
679  break;
680  }
681  case UMULH_x: {
682  mnemonic = "umulh";
683  form = form_xxx;
684  break;
685  }
686  default: UNREACHABLE();
687  }
688  Format(instr, mnemonic, form);
689 }
690 
691 
692 void Disassembler::VisitCompareBranch(Instruction* instr) {
693  const char *mnemonic = "";
694  const char *form = "'Rt, 'BImmCmpa";
695 
696  switch (instr->Mask(CompareBranchMask)) {
697  case CBZ_w:
698  case CBZ_x: mnemonic = "cbz"; break;
699  case CBNZ_w:
700  case CBNZ_x: mnemonic = "cbnz"; break;
701  default: UNREACHABLE();
702  }
703  Format(instr, mnemonic, form);
704 }
705 
706 
707 void Disassembler::VisitTestBranch(Instruction* instr) {
708  const char *mnemonic = "";
709  // If the top bit of the immediate is clear, the tested register is
710  // disassembled as Wt, otherwise Xt. As the top bit of the immediate is
711  // encoded in bit 31 of the instruction, we can reuse the Rt form, which
712  // uses bit 31 (normally "sf") to choose the register size.
713  const char *form = "'Rt, 'IS, 'BImmTest";
714 
715  switch (instr->Mask(TestBranchMask)) {
716  case TBZ: mnemonic = "tbz"; break;
717  case TBNZ: mnemonic = "tbnz"; break;
718  default: UNREACHABLE();
719  }
720  Format(instr, mnemonic, form);
721 }
722 
723 
724 void Disassembler::VisitMoveWideImmediate(Instruction* instr) {
725  const char *mnemonic = "";
726  const char *form = "'Rd, 'IMoveImm";
727 
728  // Print the shift separately for movk, to make it clear which half word will
729  // be overwritten. Movn and movz print the computed immediate, which includes
730  // shift calculation.
731  switch (instr->Mask(MoveWideImmediateMask)) {
732  case MOVN_w:
733  case MOVN_x: mnemonic = "movn"; break;
734  case MOVZ_w:
735  case MOVZ_x: mnemonic = "movz"; break;
736  case MOVK_w:
737  case MOVK_x: mnemonic = "movk"; form = "'Rd, 'IMoveLSL"; break;
738  default: UNREACHABLE();
739  }
740  Format(instr, mnemonic, form);
741 }
742 
743 
744 #define LOAD_STORE_LIST(V) \
745  V(STRB_w, "strb", "'Wt") \
746  V(STRH_w, "strh", "'Wt") \
747  V(STR_w, "str", "'Wt") \
748  V(STR_x, "str", "'Xt") \
749  V(LDRB_w, "ldrb", "'Wt") \
750  V(LDRH_w, "ldrh", "'Wt") \
751  V(LDR_w, "ldr", "'Wt") \
752  V(LDR_x, "ldr", "'Xt") \
753  V(LDRSB_x, "ldrsb", "'Xt") \
754  V(LDRSH_x, "ldrsh", "'Xt") \
755  V(LDRSW_x, "ldrsw", "'Xt") \
756  V(LDRSB_w, "ldrsb", "'Wt") \
757  V(LDRSH_w, "ldrsh", "'Wt") \
758  V(STR_s, "str", "'St") \
759  V(STR_d, "str", "'Dt") \
760  V(LDR_s, "ldr", "'St") \
761  V(LDR_d, "ldr", "'Dt")
762 
763 void Disassembler::VisitLoadStorePreIndex(Instruction* instr) {
764  const char *mnemonic = "unimplemented";
765  const char *form = "(LoadStorePreIndex)";
766 
767  switch (instr->Mask(LoadStorePreIndexMask)) {
768  #define LS_PREINDEX(A, B, C) \
769  case A##_pre: mnemonic = B; form = C ", ['Xns'ILS]!"; break;
770  LOAD_STORE_LIST(LS_PREINDEX)
771  #undef LS_PREINDEX
772  }
773  Format(instr, mnemonic, form);
774 }
775 
776 
777 void Disassembler::VisitLoadStorePostIndex(Instruction* instr) {
778  const char *mnemonic = "unimplemented";
779  const char *form = "(LoadStorePostIndex)";
780 
781  switch (instr->Mask(LoadStorePostIndexMask)) {
782  #define LS_POSTINDEX(A, B, C) \
783  case A##_post: mnemonic = B; form = C ", ['Xns]'ILS"; break;
784  LOAD_STORE_LIST(LS_POSTINDEX)
785  #undef LS_POSTINDEX
786  }
787  Format(instr, mnemonic, form);
788 }
789 
790 
791 void Disassembler::VisitLoadStoreUnsignedOffset(Instruction* instr) {
792  const char *mnemonic = "unimplemented";
793  const char *form = "(LoadStoreUnsignedOffset)";
794 
795  switch (instr->Mask(LoadStoreUnsignedOffsetMask)) {
796  #define LS_UNSIGNEDOFFSET(A, B, C) \
797  case A##_unsigned: mnemonic = B; form = C ", ['Xns'ILU]"; break;
798  LOAD_STORE_LIST(LS_UNSIGNEDOFFSET)
799  #undef LS_UNSIGNEDOFFSET
800  case PRFM_unsigned: mnemonic = "prfm"; form = "'PrefOp, ['Xn'ILU]";
801  }
802  Format(instr, mnemonic, form);
803 }
804 
805 
806 void Disassembler::VisitLoadStoreRegisterOffset(Instruction* instr) {
807  const char *mnemonic = "unimplemented";
808  const char *form = "(LoadStoreRegisterOffset)";
809 
810  switch (instr->Mask(LoadStoreRegisterOffsetMask)) {
811  #define LS_REGISTEROFFSET(A, B, C) \
812  case A##_reg: mnemonic = B; form = C ", ['Xns, 'Offsetreg]"; break;
813  LOAD_STORE_LIST(LS_REGISTEROFFSET)
814  #undef LS_REGISTEROFFSET
815  case PRFM_reg: mnemonic = "prfm"; form = "'PrefOp, ['Xns, 'Offsetreg]";
816  }
817  Format(instr, mnemonic, form);
818 }
819 
820 
821 void Disassembler::VisitLoadStoreUnscaledOffset(Instruction* instr) {
822  const char *mnemonic = "unimplemented";
823  const char *form = "'Wt, ['Xns'ILS]";
824  const char *form_x = "'Xt, ['Xns'ILS]";
825  const char *form_s = "'St, ['Xns'ILS]";
826  const char *form_d = "'Dt, ['Xns'ILS]";
827 
828  switch (instr->Mask(LoadStoreUnscaledOffsetMask)) {
829  case STURB_w: mnemonic = "sturb"; break;
830  case STURH_w: mnemonic = "sturh"; break;
831  case STUR_w: mnemonic = "stur"; break;
832  case STUR_x: mnemonic = "stur"; form = form_x; break;
833  case STUR_s: mnemonic = "stur"; form = form_s; break;
834  case STUR_d: mnemonic = "stur"; form = form_d; break;
835  case LDURB_w: mnemonic = "ldurb"; break;
836  case LDURH_w: mnemonic = "ldurh"; break;
837  case LDUR_w: mnemonic = "ldur"; break;
838  case LDUR_x: mnemonic = "ldur"; form = form_x; break;
839  case LDUR_s: mnemonic = "ldur"; form = form_s; break;
840  case LDUR_d: mnemonic = "ldur"; form = form_d; break;
841  case LDURSB_x: form = form_x; // Fall through.
842  case LDURSB_w: mnemonic = "ldursb"; break;
843  case LDURSH_x: form = form_x; // Fall through.
844  case LDURSH_w: mnemonic = "ldursh"; break;
845  case LDURSW_x: mnemonic = "ldursw"; form = form_x; break;
846  default: form = "(LoadStoreUnscaledOffset)";
847  }
848  Format(instr, mnemonic, form);
849 }
850 
851 
852 void Disassembler::VisitLoadLiteral(Instruction* instr) {
853  const char *mnemonic = "ldr";
854  const char *form = "(LoadLiteral)";
855 
856  switch (instr->Mask(LoadLiteralMask)) {
857  case LDR_w_lit: form = "'Wt, 'ILLiteral 'LValue"; break;
858  case LDR_x_lit: form = "'Xt, 'ILLiteral 'LValue"; break;
859  case LDR_s_lit: form = "'St, 'ILLiteral 'LValue"; break;
860  case LDR_d_lit: form = "'Dt, 'ILLiteral 'LValue"; break;
861  default: mnemonic = "unimplemented";
862  }
863  Format(instr, mnemonic, form);
864 }
865 
866 
867 #define LOAD_STORE_PAIR_LIST(V) \
868  V(STP_w, "stp", "'Wt, 'Wt2", "4") \
869  V(LDP_w, "ldp", "'Wt, 'Wt2", "4") \
870  V(LDPSW_x, "ldpsw", "'Xt, 'Xt2", "4") \
871  V(STP_x, "stp", "'Xt, 'Xt2", "8") \
872  V(LDP_x, "ldp", "'Xt, 'Xt2", "8") \
873  V(STP_s, "stp", "'St, 'St2", "4") \
874  V(LDP_s, "ldp", "'St, 'St2", "4") \
875  V(STP_d, "stp", "'Dt, 'Dt2", "8") \
876  V(LDP_d, "ldp", "'Dt, 'Dt2", "8")
877 
878 void Disassembler::VisitLoadStorePairPostIndex(Instruction* instr) {
879  const char *mnemonic = "unimplemented";
880  const char *form = "(LoadStorePairPostIndex)";
881 
882  switch (instr->Mask(LoadStorePairPostIndexMask)) {
883  #define LSP_POSTINDEX(A, B, C, D) \
884  case A##_post: mnemonic = B; form = C ", ['Xns]'ILP" D; break;
885  LOAD_STORE_PAIR_LIST(LSP_POSTINDEX)
886  #undef LSP_POSTINDEX
887  }
888  Format(instr, mnemonic, form);
889 }
890 
891 
892 void Disassembler::VisitLoadStorePairPreIndex(Instruction* instr) {
893  const char *mnemonic = "unimplemented";
894  const char *form = "(LoadStorePairPreIndex)";
895 
896  switch (instr->Mask(LoadStorePairPreIndexMask)) {
897  #define LSP_PREINDEX(A, B, C, D) \
898  case A##_pre: mnemonic = B; form = C ", ['Xns'ILP" D "]!"; break;
899  LOAD_STORE_PAIR_LIST(LSP_PREINDEX)
900  #undef LSP_PREINDEX
901  }
902  Format(instr, mnemonic, form);
903 }
904 
905 
906 void Disassembler::VisitLoadStorePairOffset(Instruction* instr) {
907  const char *mnemonic = "unimplemented";
908  const char *form = "(LoadStorePairOffset)";
909 
910  switch (instr->Mask(LoadStorePairOffsetMask)) {
911  #define LSP_OFFSET(A, B, C, D) \
912  case A##_off: mnemonic = B; form = C ", ['Xns'ILP" D "]"; break;
913  LOAD_STORE_PAIR_LIST(LSP_OFFSET)
914  #undef LSP_OFFSET
915  }
916  Format(instr, mnemonic, form);
917 }
918 
919 
920 void Disassembler::VisitLoadStorePairNonTemporal(Instruction* instr) {
921  const char *mnemonic = "unimplemented";
922  const char *form;
923 
924  switch (instr->Mask(LoadStorePairNonTemporalMask)) {
925  case STNP_w: mnemonic = "stnp"; form = "'Wt, 'Wt2, ['Xns'ILP4]"; break;
926  case LDNP_w: mnemonic = "ldnp"; form = "'Wt, 'Wt2, ['Xns'ILP4]"; break;
927  case STNP_x: mnemonic = "stnp"; form = "'Xt, 'Xt2, ['Xns'ILP8]"; break;
928  case LDNP_x: mnemonic = "ldnp"; form = "'Xt, 'Xt2, ['Xns'ILP8]"; break;
929  case STNP_s: mnemonic = "stnp"; form = "'St, 'St2, ['Xns'ILP4]"; break;
930  case LDNP_s: mnemonic = "ldnp"; form = "'St, 'St2, ['Xns'ILP4]"; break;
931  case STNP_d: mnemonic = "stnp"; form = "'Dt, 'Dt2, ['Xns'ILP8]"; break;
932  case LDNP_d: mnemonic = "ldnp"; form = "'Dt, 'Dt2, ['Xns'ILP8]"; break;
933  default: form = "(LoadStorePairNonTemporal)";
934  }
935  Format(instr, mnemonic, form);
936 }
937 
938 
939 void Disassembler::VisitFPCompare(Instruction* instr) {
940  const char *mnemonic = "unimplemented";
941  const char *form = "'Fn, 'Fm";
942  const char *form_zero = "'Fn, #0.0";
943 
944  switch (instr->Mask(FPCompareMask)) {
945  case FCMP_s_zero:
946  case FCMP_d_zero: form = form_zero; // Fall through.
947  case FCMP_s:
948  case FCMP_d: mnemonic = "fcmp"; break;
949  default: form = "(FPCompare)";
950  }
951  Format(instr, mnemonic, form);
952 }
953 
954 
955 void Disassembler::VisitFPConditionalCompare(Instruction* instr) {
956  const char *mnemonic = "unimplemented";
957  const char *form = "'Fn, 'Fm, 'INzcv, 'Cond";
958 
959  switch (instr->Mask(FPConditionalCompareMask)) {
960  case FCCMP_s:
961  case FCCMP_d: mnemonic = "fccmp"; break;
962  case FCCMPE_s:
963  case FCCMPE_d: mnemonic = "fccmpe"; break;
964  default: form = "(FPConditionalCompare)";
965  }
966  Format(instr, mnemonic, form);
967 }
968 
969 
970 void Disassembler::VisitFPConditionalSelect(Instruction* instr) {
971  const char *mnemonic = "";
972  const char *form = "'Fd, 'Fn, 'Fm, 'Cond";
973 
974  switch (instr->Mask(FPConditionalSelectMask)) {
975  case FCSEL_s:
976  case FCSEL_d: mnemonic = "fcsel"; break;
977  default: UNREACHABLE();
978  }
979  Format(instr, mnemonic, form);
980 }
981 
982 
983 void Disassembler::VisitFPDataProcessing1Source(Instruction* instr) {
984  const char *mnemonic = "unimplemented";
985  const char *form = "'Fd, 'Fn";
986 
987  switch (instr->Mask(FPDataProcessing1SourceMask)) {
988  #define FORMAT(A, B) \
989  case A##_s: \
990  case A##_d: mnemonic = B; break;
991  FORMAT(FMOV, "fmov");
992  FORMAT(FABS, "fabs");
993  FORMAT(FNEG, "fneg");
994  FORMAT(FSQRT, "fsqrt");
995  FORMAT(FRINTN, "frintn");
996  FORMAT(FRINTP, "frintp");
997  FORMAT(FRINTM, "frintm");
998  FORMAT(FRINTZ, "frintz");
999  FORMAT(FRINTA, "frinta");
1000  FORMAT(FRINTX, "frintx");
1001  FORMAT(FRINTI, "frinti");
1002  #undef FORMAT
1003  case FCVT_ds: mnemonic = "fcvt"; form = "'Dd, 'Sn"; break;
1004  case FCVT_sd: mnemonic = "fcvt"; form = "'Sd, 'Dn"; break;
1005  default: form = "(FPDataProcessing1Source)";
1006  }
1007  Format(instr, mnemonic, form);
1008 }
1009 
1010 
1011 void Disassembler::VisitFPDataProcessing2Source(Instruction* instr) {
1012  const char *mnemonic = "";
1013  const char *form = "'Fd, 'Fn, 'Fm";
1014 
1015  switch (instr->Mask(FPDataProcessing2SourceMask)) {
1016  #define FORMAT(A, B) \
1017  case A##_s: \
1018  case A##_d: mnemonic = B; break;
1019  FORMAT(FMUL, "fmul");
1020  FORMAT(FDIV, "fdiv");
1021  FORMAT(FADD, "fadd");
1022  FORMAT(FSUB, "fsub");
1023  FORMAT(FMAX, "fmax");
1024  FORMAT(FMIN, "fmin");
1025  FORMAT(FMAXNM, "fmaxnm");
1026  FORMAT(FMINNM, "fminnm");
1027  FORMAT(FNMUL, "fnmul");
1028  #undef FORMAT
1029  default: UNREACHABLE();
1030  }
1031  Format(instr, mnemonic, form);
1032 }
1033 
1034 
1035 void Disassembler::VisitFPDataProcessing3Source(Instruction* instr) {
1036  const char *mnemonic = "";
1037  const char *form = "'Fd, 'Fn, 'Fm, 'Fa";
1038 
1039  switch (instr->Mask(FPDataProcessing3SourceMask)) {
1040  #define FORMAT(A, B) \
1041  case A##_s: \
1042  case A##_d: mnemonic = B; break;
1043  FORMAT(FMADD, "fmadd");
1044  FORMAT(FMSUB, "fmsub");
1045  FORMAT(FNMADD, "fnmadd");
1046  FORMAT(FNMSUB, "fnmsub");
1047  #undef FORMAT
1048  default: UNREACHABLE();
1049  }
1050  Format(instr, mnemonic, form);
1051 }
1052 
1053 
1054 void Disassembler::VisitFPImmediate(Instruction* instr) {
1055  const char *mnemonic = "";
1056  const char *form = "(FPImmediate)";
1057 
1058  switch (instr->Mask(FPImmediateMask)) {
1059  case FMOV_s_imm: mnemonic = "fmov"; form = "'Sd, 'IFPSingle"; break;
1060  case FMOV_d_imm: mnemonic = "fmov"; form = "'Dd, 'IFPDouble"; break;
1061  default: UNREACHABLE();
1062  }
1063  Format(instr, mnemonic, form);
1064 }
1065 
1066 
1067 void Disassembler::VisitFPIntegerConvert(Instruction* instr) {
1068  const char *mnemonic = "unimplemented";
1069  const char *form = "(FPIntegerConvert)";
1070  const char *form_rf = "'Rd, 'Fn";
1071  const char *form_fr = "'Fd, 'Rn";
1072 
1073  switch (instr->Mask(FPIntegerConvertMask)) {
1074  case FMOV_ws:
1075  case FMOV_xd: mnemonic = "fmov"; form = form_rf; break;
1076  case FMOV_sw:
1077  case FMOV_dx: mnemonic = "fmov"; form = form_fr; break;
1078  case FCVTAS_ws:
1079  case FCVTAS_xs:
1080  case FCVTAS_wd:
1081  case FCVTAS_xd: mnemonic = "fcvtas"; form = form_rf; break;
1082  case FCVTAU_ws:
1083  case FCVTAU_xs:
1084  case FCVTAU_wd:
1085  case FCVTAU_xd: mnemonic = "fcvtau"; form = form_rf; break;
1086  case FCVTMS_ws:
1087  case FCVTMS_xs:
1088  case FCVTMS_wd:
1089  case FCVTMS_xd: mnemonic = "fcvtms"; form = form_rf; break;
1090  case FCVTMU_ws:
1091  case FCVTMU_xs:
1092  case FCVTMU_wd:
1093  case FCVTMU_xd: mnemonic = "fcvtmu"; form = form_rf; break;
1094  case FCVTNS_ws:
1095  case FCVTNS_xs:
1096  case FCVTNS_wd:
1097  case FCVTNS_xd: mnemonic = "fcvtns"; form = form_rf; break;
1098  case FCVTNU_ws:
1099  case FCVTNU_xs:
1100  case FCVTNU_wd:
1101  case FCVTNU_xd: mnemonic = "fcvtnu"; form = form_rf; break;
1102  case FCVTZU_xd:
1103  case FCVTZU_ws:
1104  case FCVTZU_wd:
1105  case FCVTZU_xs: mnemonic = "fcvtzu"; form = form_rf; break;
1106  case FCVTZS_xd:
1107  case FCVTZS_wd:
1108  case FCVTZS_xs:
1109  case FCVTZS_ws: mnemonic = "fcvtzs"; form = form_rf; break;
1110  case SCVTF_sw:
1111  case SCVTF_sx:
1112  case SCVTF_dw:
1113  case SCVTF_dx: mnemonic = "scvtf"; form = form_fr; break;
1114  case UCVTF_sw:
1115  case UCVTF_sx:
1116  case UCVTF_dw:
1117  case UCVTF_dx: mnemonic = "ucvtf"; form = form_fr; break;
1118  }
1119  Format(instr, mnemonic, form);
1120 }
1121 
1122 
1123 void Disassembler::VisitFPFixedPointConvert(Instruction* instr) {
1124  const char *mnemonic = "";
1125  const char *form = "'Rd, 'Fn, 'IFPFBits";
1126  const char *form_fr = "'Fd, 'Rn, 'IFPFBits";
1127 
1128  switch (instr->Mask(FPFixedPointConvertMask)) {
1129  case FCVTZS_ws_fixed:
1130  case FCVTZS_xs_fixed:
1131  case FCVTZS_wd_fixed:
1132  case FCVTZS_xd_fixed: mnemonic = "fcvtzs"; break;
1133  case FCVTZU_ws_fixed:
1134  case FCVTZU_xs_fixed:
1135  case FCVTZU_wd_fixed:
1136  case FCVTZU_xd_fixed: mnemonic = "fcvtzu"; break;
1137  case SCVTF_sw_fixed:
1138  case SCVTF_sx_fixed:
1139  case SCVTF_dw_fixed:
1140  case SCVTF_dx_fixed: mnemonic = "scvtf"; form = form_fr; break;
1141  case UCVTF_sw_fixed:
1142  case UCVTF_sx_fixed:
1143  case UCVTF_dw_fixed:
1144  case UCVTF_dx_fixed: mnemonic = "ucvtf"; form = form_fr; break;
1145  }
1146  Format(instr, mnemonic, form);
1147 }
1148 
1149 
1150 void Disassembler::VisitSystem(Instruction* instr) {
1151  // Some system instructions hijack their Op and Cp fields to represent a
1152  // range of immediates instead of indicating a different instruction. This
1153  // makes the decoding tricky.
1154  const char *mnemonic = "unimplemented";
1155  const char *form = "(System)";
1156 
1157  if (instr->Mask(SystemSysRegFMask) == SystemSysRegFixed) {
1158  switch (instr->Mask(SystemSysRegMask)) {
1159  case MRS: {
1160  mnemonic = "mrs";
1161  switch (instr->ImmSystemRegister()) {
1162  case NZCV: form = "'Xt, nzcv"; break;
1163  case FPCR: form = "'Xt, fpcr"; break;
1164  default: form = "'Xt, (unknown)"; break;
1165  }
1166  break;
1167  }
1168  case MSR: {
1169  mnemonic = "msr";
1170  switch (instr->ImmSystemRegister()) {
1171  case NZCV: form = "nzcv, 'Xt"; break;
1172  case FPCR: form = "fpcr, 'Xt"; break;
1173  default: form = "(unknown), 'Xt"; break;
1174  }
1175  break;
1176  }
1177  }
1178  } else if (instr->Mask(SystemHintFMask) == SystemHintFixed) {
1179  DCHECK(instr->Mask(SystemHintMask) == HINT);
1180  switch (instr->ImmHint()) {
1181  case NOP: {
1182  mnemonic = "nop";
1183  form = NULL;
1184  break;
1185  }
1186  }
1187  } else if (instr->Mask(MemBarrierFMask) == MemBarrierFixed) {
1188  switch (instr->Mask(MemBarrierMask)) {
1189  case DMB: {
1190  mnemonic = "dmb";
1191  form = "'M";
1192  break;
1193  }
1194  case DSB: {
1195  mnemonic = "dsb";
1196  form = "'M";
1197  break;
1198  }
1199  case ISB: {
1200  mnemonic = "isb";
1201  form = NULL;
1202  break;
1203  }
1204  }
1205  }
1206 
1207  Format(instr, mnemonic, form);
1208 }
1209 
1210 
1211 void Disassembler::VisitException(Instruction* instr) {
1212  const char *mnemonic = "unimplemented";
1213  const char *form = "'IDebug";
1214 
1215  switch (instr->Mask(ExceptionMask)) {
1216  case HLT: mnemonic = "hlt"; break;
1217  case BRK: mnemonic = "brk"; break;
1218  case SVC: mnemonic = "svc"; break;
1219  case HVC: mnemonic = "hvc"; break;
1220  case SMC: mnemonic = "smc"; break;
1221  case DCPS1: mnemonic = "dcps1"; form = "{'IDebug}"; break;
1222  case DCPS2: mnemonic = "dcps2"; form = "{'IDebug}"; break;
1223  case DCPS3: mnemonic = "dcps3"; form = "{'IDebug}"; break;
1224  default: form = "(Exception)";
1225  }
1226  Format(instr, mnemonic, form);
1227 }
1228 
1229 
1230 void Disassembler::VisitUnimplemented(Instruction* instr) {
1231  Format(instr, "unimplemented", "(Unimplemented)");
1232 }
1233 
1234 
1235 void Disassembler::VisitUnallocated(Instruction* instr) {
1236  Format(instr, "unallocated", "(Unallocated)");
1237 }
1238 
1239 
1240 void Disassembler::ProcessOutput(Instruction* /*instr*/) {
1241  // The base disasm does nothing more than disassembling into a buffer.
1242 }
1243 
1244 
1245 void Disassembler::Format(Instruction* instr, const char* mnemonic,
1246  const char* format) {
1247  // TODO(mcapewel) don't think I can use the instr address here - there needs
1248  // to be a base address too
1249  DCHECK(mnemonic != NULL);
1250  ResetOutput();
1251  Substitute(instr, mnemonic);
1252  if (format != NULL) {
1253  buffer_[buffer_pos_++] = ' ';
1254  Substitute(instr, format);
1255  }
1256  buffer_[buffer_pos_] = 0;
1257  ProcessOutput(instr);
1258 }
1259 
1260 
1261 void Disassembler::Substitute(Instruction* instr, const char* string) {
1262  char chr = *string++;
1263  while (chr != '\0') {
1264  if (chr == '\'') {
1265  string += SubstituteField(instr, string);
1266  } else {
1267  buffer_[buffer_pos_++] = chr;
1268  }
1269  chr = *string++;
1270  }
1271 }
1272 
1273 
1274 int Disassembler::SubstituteField(Instruction* instr, const char* format) {
1275  switch (format[0]) {
1276  case 'R': // Register. X or W, selected by sf bit.
1277  case 'F': // FP Register. S or D, selected by type field.
1278  case 'W':
1279  case 'X':
1280  case 'S':
1281  case 'D': return SubstituteRegisterField(instr, format);
1282  case 'I': return SubstituteImmediateField(instr, format);
1283  case 'L': return SubstituteLiteralField(instr, format);
1284  case 'H': return SubstituteShiftField(instr, format);
1285  case 'P': return SubstitutePrefetchField(instr, format);
1286  case 'C': return SubstituteConditionField(instr, format);
1287  case 'E': return SubstituteExtendField(instr, format);
1288  case 'A': return SubstitutePCRelAddressField(instr, format);
1289  case 'B': return SubstituteBranchTargetField(instr, format);
1290  case 'O': return SubstituteLSRegOffsetField(instr, format);
1291  case 'M': return SubstituteBarrierField(instr, format);
1292  default: {
1293  UNREACHABLE();
1294  return 1;
1295  }
1296  }
1297 }
1298 
1299 
1300 int Disassembler::SubstituteRegisterField(Instruction* instr,
1301  const char* format) {
1302  unsigned reg_num = 0;
1303  unsigned field_len = 2;
1304  switch (format[1]) {
1305  case 'd': reg_num = instr->Rd(); break;
1306  case 'n': reg_num = instr->Rn(); break;
1307  case 'm': reg_num = instr->Rm(); break;
1308  case 'a': reg_num = instr->Ra(); break;
1309  case 't': {
1310  if (format[2] == '2') {
1311  reg_num = instr->Rt2();
1312  field_len = 3;
1313  } else {
1314  reg_num = instr->Rt();
1315  }
1316  break;
1317  }
1318  default: UNREACHABLE();
1319  }
1320 
1321  // Increase field length for registers tagged as stack.
1322  if (format[2] == 's') {
1323  field_len = 3;
1324  }
1325 
1326  char reg_type;
1327  if (format[0] == 'R') {
1328  // Register type is R: use sf bit to choose X and W.
1329  reg_type = instr->SixtyFourBits() ? 'x' : 'w';
1330  } else if (format[0] == 'F') {
1331  // Floating-point register: use type field to choose S or D.
1332  reg_type = ((instr->FPType() & 1) == 0) ? 's' : 'd';
1333  } else {
1334  // Register type is specified. Make it lower case.
1335  reg_type = format[0] + 0x20;
1336  }
1337 
1338  if ((reg_num != kZeroRegCode) || (reg_type == 's') || (reg_type == 'd')) {
1339  // A normal register: w0 - w30, x0 - x30, s0 - s31, d0 - d31.
1340 
1341  // Filter special registers
1342  if ((reg_type == 'x') && (reg_num == 27)) {
1343  AppendToOutput("cp");
1344  } else if ((reg_type == 'x') && (reg_num == 28)) {
1345  AppendToOutput("jssp");
1346  } else if ((reg_type == 'x') && (reg_num == 29)) {
1347  AppendToOutput("fp");
1348  } else if ((reg_type == 'x') && (reg_num == 30)) {
1349  AppendToOutput("lr");
1350  } else {
1351  AppendToOutput("%c%d", reg_type, reg_num);
1352  }
1353  } else if (format[2] == 's') {
1354  // Disassemble w31/x31 as stack pointer wcsp/csp.
1355  AppendToOutput("%s", (reg_type == 'w') ? "wcsp" : "csp");
1356  } else {
1357  // Disassemble w31/x31 as zero register wzr/xzr.
1358  AppendToOutput("%czr", reg_type);
1359  }
1360 
1361  return field_len;
1362 }
1363 
1364 
1365 int Disassembler::SubstituteImmediateField(Instruction* instr,
1366  const char* format) {
1367  DCHECK(format[0] == 'I');
1368 
1369  switch (format[1]) {
1370  case 'M': { // IMoveImm or IMoveLSL.
1371  if (format[5] == 'I') {
1372  uint64_t imm = instr->ImmMoveWide() << (16 * instr->ShiftMoveWide());
1373  AppendToOutput("#0x%" PRIx64, imm);
1374  } else {
1375  DCHECK(format[5] == 'L');
1376  AppendToOutput("#0x%" PRIx64, instr->ImmMoveWide());
1377  if (instr->ShiftMoveWide() > 0) {
1378  AppendToOutput(", lsl #%d", 16 * instr->ShiftMoveWide());
1379  }
1380  }
1381  return 8;
1382  }
1383  case 'L': {
1384  switch (format[2]) {
1385  case 'L': { // ILLiteral - Immediate Load Literal.
1386  AppendToOutput("pc%+" PRId64,
1387  instr->ImmLLiteral() << kLoadLiteralScaleLog2);
1388  return 9;
1389  }
1390  case 'S': { // ILS - Immediate Load/Store.
1391  if (instr->ImmLS() != 0) {
1392  AppendToOutput(", #%" PRId64, instr->ImmLS());
1393  }
1394  return 3;
1395  }
1396  case 'P': { // ILPx - Immediate Load/Store Pair, x = access size.
1397  if (instr->ImmLSPair() != 0) {
1398  // format[3] is the scale value. Convert to a number.
1399  int scale = format[3] - 0x30;
1400  AppendToOutput(", #%" PRId64, instr->ImmLSPair() * scale);
1401  }
1402  return 4;
1403  }
1404  case 'U': { // ILU - Immediate Load/Store Unsigned.
1405  if (instr->ImmLSUnsigned() != 0) {
1406  AppendToOutput(", #%" PRIu64,
1407  instr->ImmLSUnsigned() << instr->SizeLS());
1408  }
1409  return 3;
1410  }
1411  }
1412  }
1413  case 'C': { // ICondB - Immediate Conditional Branch.
1414  int64_t offset = instr->ImmCondBranch() << 2;
1415  char sign = (offset >= 0) ? '+' : '-';
1416  AppendToOutput("#%c0x%" PRIx64, sign, offset);
1417  return 6;
1418  }
1419  case 'A': { // IAddSub.
1420  DCHECK(instr->ShiftAddSub() <= 1);
1421  int64_t imm = instr->ImmAddSub() << (12 * instr->ShiftAddSub());
1422  AppendToOutput("#0x%" PRIx64 " (%" PRId64 ")", imm, imm);
1423  return 7;
1424  }
1425  case 'F': { // IFPSingle, IFPDouble or IFPFBits.
1426  if (format[3] == 'F') { // IFPFBits.
1427  AppendToOutput("#%d", 64 - instr->FPScale());
1428  return 8;
1429  } else {
1430  AppendToOutput("#0x%" PRIx64 " (%.4f)", instr->ImmFP(),
1431  format[3] == 'S' ? instr->ImmFP32() : instr->ImmFP64());
1432  return 9;
1433  }
1434  }
1435  case 'T': { // ITri - Immediate Triangular Encoded.
1436  AppendToOutput("#0x%" PRIx64, instr->ImmLogical());
1437  return 4;
1438  }
1439  case 'N': { // INzcv.
1440  int nzcv = (instr->Nzcv() << Flags_offset);
1441  AppendToOutput("#%c%c%c%c", ((nzcv & NFlag) == 0) ? 'n' : 'N',
1442  ((nzcv & ZFlag) == 0) ? 'z' : 'Z',
1443  ((nzcv & CFlag) == 0) ? 'c' : 'C',
1444  ((nzcv & VFlag) == 0) ? 'v' : 'V');
1445  return 5;
1446  }
1447  case 'P': { // IP - Conditional compare.
1448  AppendToOutput("#%d", instr->ImmCondCmp());
1449  return 2;
1450  }
1451  case 'B': { // Bitfields.
1452  return SubstituteBitfieldImmediateField(instr, format);
1453  }
1454  case 'E': { // IExtract.
1455  AppendToOutput("#%d", instr->ImmS());
1456  return 8;
1457  }
1458  case 'S': { // IS - Test and branch bit.
1459  AppendToOutput("#%d", (instr->ImmTestBranchBit5() << 5) |
1460  instr->ImmTestBranchBit40());
1461  return 2;
1462  }
1463  case 'D': { // IDebug - HLT and BRK instructions.
1464  AppendToOutput("#0x%x", instr->ImmException());
1465  return 6;
1466  }
1467  default: {
1468  UNREACHABLE();
1469  return 0;
1470  }
1471  }
1472 }
1473 
1474 
1475 int Disassembler::SubstituteBitfieldImmediateField(Instruction* instr,
1476  const char* format) {
1477  DCHECK((format[0] == 'I') && (format[1] == 'B'));
1478  unsigned r = instr->ImmR();
1479  unsigned s = instr->ImmS();
1480 
1481  switch (format[2]) {
1482  case 'r': { // IBr.
1483  AppendToOutput("#%d", r);
1484  return 3;
1485  }
1486  case 's': { // IBs+1 or IBs-r+1.
1487  if (format[3] == '+') {
1488  AppendToOutput("#%d", s + 1);
1489  return 5;
1490  } else {
1491  DCHECK(format[3] == '-');
1492  AppendToOutput("#%d", s - r + 1);
1493  return 7;
1494  }
1495  }
1496  case 'Z': { // IBZ-r.
1497  DCHECK((format[3] == '-') && (format[4] == 'r'));
1498  unsigned reg_size = (instr->SixtyFourBits() == 1) ? kXRegSizeInBits
1499  : kWRegSizeInBits;
1500  AppendToOutput("#%d", reg_size - r);
1501  return 5;
1502  }
1503  default: {
1504  UNREACHABLE();
1505  return 0;
1506  }
1507  }
1508 }
1509 
1510 
1511 int Disassembler::SubstituteLiteralField(Instruction* instr,
1512  const char* format) {
1513  DCHECK(strncmp(format, "LValue", 6) == 0);
1514  USE(format);
1515 
1516  switch (instr->Mask(LoadLiteralMask)) {
1517  case LDR_w_lit:
1518  case LDR_x_lit:
1519  case LDR_s_lit:
1520  case LDR_d_lit:
1521  AppendToOutput("(addr 0x%016" PRIxPTR ")", instr->LiteralAddress());
1522  break;
1523  default: UNREACHABLE();
1524  }
1525 
1526  return 6;
1527 }
1528 
1529 
1530 int Disassembler::SubstituteShiftField(Instruction* instr, const char* format) {
1531  DCHECK(format[0] == 'H');
1532  DCHECK(instr->ShiftDP() <= 0x3);
1533 
1534  switch (format[1]) {
1535  case 'D': { // HDP.
1536  DCHECK(instr->ShiftDP() != ROR);
1537  } // Fall through.
1538  case 'L': { // HLo.
1539  if (instr->ImmDPShift() != 0) {
1540  const char* shift_type[] = {"lsl", "lsr", "asr", "ror"};
1541  AppendToOutput(", %s #%" PRId64, shift_type[instr->ShiftDP()],
1542  instr->ImmDPShift());
1543  }
1544  return 3;
1545  }
1546  default:
1547  UNREACHABLE();
1548  return 0;
1549  }
1550 }
1551 
1552 
1553 int Disassembler::SubstituteConditionField(Instruction* instr,
1554  const char* format) {
1555  DCHECK(format[0] == 'C');
1556  const char* condition_code[] = { "eq", "ne", "hs", "lo",
1557  "mi", "pl", "vs", "vc",
1558  "hi", "ls", "ge", "lt",
1559  "gt", "le", "al", "nv" };
1560  int cond;
1561  switch (format[1]) {
1562  case 'B': cond = instr->ConditionBranch(); break;
1563  case 'I': {
1564  cond = NegateCondition(static_cast<Condition>(instr->Condition()));
1565  break;
1566  }
1567  default: cond = instr->Condition();
1568  }
1569  AppendToOutput("%s", condition_code[cond]);
1570  return 4;
1571 }
1572 
1573 
1574 int Disassembler::SubstitutePCRelAddressField(Instruction* instr,
1575  const char* format) {
1576  USE(format);
1577  DCHECK(strncmp(format, "AddrPCRel", 9) == 0);
1578 
1579  int offset = instr->ImmPCRel();
1580 
1581  // Only ADR (AddrPCRelByte) is supported.
1582  DCHECK(strcmp(format, "AddrPCRelByte") == 0);
1583 
1584  char sign = '+';
1585  if (offset < 0) {
1586  offset = -offset;
1587  sign = '-';
1588  }
1589  AppendToOutput("#%c0x%x (addr %p)", sign, offset,
1590  instr->InstructionAtOffset(offset, Instruction::NO_CHECK));
1591  return 13;
1592 }
1593 
1594 
1595 int Disassembler::SubstituteBranchTargetField(Instruction* instr,
1596  const char* format) {
1597  DCHECK(strncmp(format, "BImm", 4) == 0);
1598 
1599  int64_t offset = 0;
1600  switch (format[5]) {
1601  // BImmUncn - unconditional branch immediate.
1602  case 'n': offset = instr->ImmUncondBranch(); break;
1603  // BImmCond - conditional branch immediate.
1604  case 'o': offset = instr->ImmCondBranch(); break;
1605  // BImmCmpa - compare and branch immediate.
1606  case 'm': offset = instr->ImmCmpBranch(); break;
1607  // BImmTest - test and branch immediate.
1608  case 'e': offset = instr->ImmTestBranch(); break;
1609  default: UNREACHABLE();
1610  }
1611  offset <<= kInstructionSizeLog2;
1612  char sign = '+';
1613  if (offset < 0) {
1614  sign = '-';
1615  }
1616  AppendToOutput("#%c0x%" PRIx64 " (addr %p)", sign, Abs(offset),
1617  instr->InstructionAtOffset(offset), Instruction::NO_CHECK);
1618  return 8;
1619 }
1620 
1621 
1622 int Disassembler::SubstituteExtendField(Instruction* instr,
1623  const char* format) {
1624  DCHECK(strncmp(format, "Ext", 3) == 0);
1625  DCHECK(instr->ExtendMode() <= 7);
1626  USE(format);
1627 
1628  const char* extend_mode[] = { "uxtb", "uxth", "uxtw", "uxtx",
1629  "sxtb", "sxth", "sxtw", "sxtx" };
1630 
1631  // If rd or rn is SP, uxtw on 32-bit registers and uxtx on 64-bit
1632  // registers becomes lsl.
1633  if (((instr->Rd() == kZeroRegCode) || (instr->Rn() == kZeroRegCode)) &&
1634  (((instr->ExtendMode() == UXTW) && (instr->SixtyFourBits() == 0)) ||
1635  (instr->ExtendMode() == UXTX))) {
1636  if (instr->ImmExtendShift() > 0) {
1637  AppendToOutput(", lsl #%d", instr->ImmExtendShift());
1638  }
1639  } else {
1640  AppendToOutput(", %s", extend_mode[instr->ExtendMode()]);
1641  if (instr->ImmExtendShift() > 0) {
1642  AppendToOutput(" #%d", instr->ImmExtendShift());
1643  }
1644  }
1645  return 3;
1646 }
1647 
1648 
1649 int Disassembler::SubstituteLSRegOffsetField(Instruction* instr,
1650  const char* format) {
1651  DCHECK(strncmp(format, "Offsetreg", 9) == 0);
1652  const char* extend_mode[] = { "undefined", "undefined", "uxtw", "lsl",
1653  "undefined", "undefined", "sxtw", "sxtx" };
1654  USE(format);
1655 
1656  unsigned shift = instr->ImmShiftLS();
1657  Extend ext = static_cast<Extend>(instr->ExtendMode());
1658  char reg_type = ((ext == UXTW) || (ext == SXTW)) ? 'w' : 'x';
1659 
1660  unsigned rm = instr->Rm();
1661  if (rm == kZeroRegCode) {
1662  AppendToOutput("%czr", reg_type);
1663  } else {
1664  AppendToOutput("%c%d", reg_type, rm);
1665  }
1666 
1667  // Extend mode UXTX is an alias for shift mode LSL here.
1668  if (!((ext == UXTX) && (shift == 0))) {
1669  AppendToOutput(", %s", extend_mode[ext]);
1670  if (shift != 0) {
1671  AppendToOutput(" #%d", instr->SizeLS());
1672  }
1673  }
1674  return 9;
1675 }
1676 
1677 
1678 int Disassembler::SubstitutePrefetchField(Instruction* instr,
1679  const char* format) {
1680  DCHECK(format[0] == 'P');
1681  USE(format);
1682 
1683  int prefetch_mode = instr->PrefetchMode();
1684 
1685  const char* ls = (prefetch_mode & 0x10) ? "st" : "ld";
1686  int level = (prefetch_mode >> 1) + 1;
1687  const char* ks = (prefetch_mode & 1) ? "strm" : "keep";
1688 
1689  AppendToOutput("p%sl%d%s", ls, level, ks);
1690  return 6;
1691 }
1692 
1693 int Disassembler::SubstituteBarrierField(Instruction* instr,
1694  const char* format) {
1695  DCHECK(format[0] == 'M');
1696  USE(format);
1697 
1698  static const char* options[4][4] = {
1699  { "sy (0b0000)", "oshld", "oshst", "osh" },
1700  { "sy (0b0100)", "nshld", "nshst", "nsh" },
1701  { "sy (0b1000)", "ishld", "ishst", "ish" },
1702  { "sy (0b1100)", "ld", "st", "sy" }
1703  };
1704  int domain = instr->ImmBarrierDomain();
1705  int type = instr->ImmBarrierType();
1706 
1707  AppendToOutput("%s", options[domain][type]);
1708  return 1;
1709 }
1710 
1711 
1713  buffer_pos_ = 0;
1714  buffer_[buffer_pos_] = 0;
1715 }
1716 
1717 
1718 void Disassembler::AppendToOutput(const char* format, ...) {
1719  va_list args;
1720  va_start(args, format);
1721  buffer_pos_ += vsnprintf(&buffer_[buffer_pos_], buffer_size_, format, args);
1722  va_end(args);
1723 }
1724 
1725 
1726 void PrintDisassembler::ProcessOutput(Instruction* instr) {
1727  fprintf(stream_, "0x%016" PRIx64 " %08" PRIx32 "\t\t%s\n",
1728  reinterpret_cast<uint64_t>(instr), instr->InstructionBits(),
1729  GetOutput());
1730 }
1731 
1732 } } // namespace v8::internal
1733 
1734 
1735 namespace disasm {
1736 
1737 
1738 const char* NameConverter::NameOfAddress(byte* addr) const {
1739  v8::internal::SNPrintF(tmp_buffer_, "%p", addr);
1740  return tmp_buffer_.start();
1741 }
1742 
1743 
1744 const char* NameConverter::NameOfConstant(byte* addr) const {
1745  return NameOfAddress(addr);
1746 }
1747 
1748 
1749 const char* NameConverter::NameOfCPURegister(int reg) const {
1750  unsigned ureg = reg; // Avoid warnings about signed/unsigned comparisons.
1751  if (ureg >= v8::internal::kNumberOfRegisters) {
1752  return "noreg";
1753  }
1754  if (ureg == v8::internal::kZeroRegCode) {
1755  return "xzr";
1756  }
1757  v8::internal::SNPrintF(tmp_buffer_, "x%u", ureg);
1758  return tmp_buffer_.start();
1759 }
1760 
1761 
1762 const char* NameConverter::NameOfByteCPURegister(int reg) const {
1763  UNREACHABLE(); // ARM64 does not have the concept of a byte register
1764  return "nobytereg";
1765 }
1766 
1767 
1768 const char* NameConverter::NameOfXMMRegister(int reg) const {
1769  UNREACHABLE(); // ARM64 does not have any XMM registers
1770  return "noxmmreg";
1771 }
1772 
1773 
1774 const char* NameConverter::NameInCode(byte* addr) const {
1775  // The default name converter is called for unknown code, so we will not try
1776  // to access any memory.
1777  return "";
1778 }
1779 
1780 
1781 //------------------------------------------------------------------------------
1782 
1783 class BufferDisassembler : public v8::internal::Disassembler {
1784  public:
1785  explicit BufferDisassembler(v8::internal::Vector<char> out_buffer)
1786  : out_buffer_(out_buffer) { }
1787 
1788  ~BufferDisassembler() { }
1789 
1790  virtual void ProcessOutput(v8::internal::Instruction* instr) {
1791  v8::internal::SNPrintF(out_buffer_, "%s", GetOutput());
1792  }
1793 
1794  private:
1795  v8::internal::Vector<char> out_buffer_;
1796 };
1797 
1798 Disassembler::Disassembler(const NameConverter& converter)
1799  : converter_(converter) {}
1800 
1801 
1802 Disassembler::~Disassembler() { USE(converter_); }
1803 
1804 
1805 int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
1806  byte* instr) {
1808  BufferDisassembler disasm(buffer);
1809  decoder.AppendVisitor(&disasm);
1810 
1811  decoder.Decode(reinterpret_cast<v8::internal::Instruction*>(instr));
1813 }
1814 
1815 
1816 int Disassembler::ConstantPoolSizeAt(byte* instr) {
1818  reinterpret_cast<v8::internal::Instruction*>(instr));
1819 }
1820 
1821 
1822 void Disassembler::Disassemble(FILE* file, byte* start, byte* end) {
1825  decoder.AppendVisitor(&disasm);
1826 
1827  for (byte* pc = start; pc < end; pc += v8::internal::kInstructionSize) {
1828  decoder.Decode(reinterpret_cast<v8::internal::Instruction*>(pc));
1829  }
1830 }
1831 
1832 } // namespace disasm
1833 
1834 #endif // V8_TARGET_ARCH_ARM64
Disassembler(const NameConverter &converter)
v8::internal::EmbeddedVector< char, 128 > tmp_buffer_
Definition: disasm.h:26
virtual const char * NameInCode(byte *addr) const
virtual const char * NameOfByteCPURegister(int reg) const
virtual const char * NameOfXMMRegister(int reg) const
virtual const char * NameOfAddress(byte *addr) const
virtual const char * NameOfCPURegister(int reg) const
virtual const char * NameOfConstant(byte *addr) const
static int ConstantPoolSizeAt(Instruction *instr)
virtual void Decode(Instruction *instr)
void Format(Instruction *instr, const char *mnemonic, const char *format)
int SubstituteBranchTargetField(Instruction *instr, const char *format)
int SubstituteExtendField(Instruction *instr, const char *format)
bool RnIsZROrSP(Instruction *instr) const
Definition: disasm-arm64.h:54
bool IsMovzMovnImm(unsigned reg_size, uint64_t value)
bool RdIsZROrSP(Instruction *instr) const
Definition: disasm-arm64.h:50
void AppendToOutput(const char *string,...)
int SubstituteField(Instruction *instr, const char *format)
bool RaIsZROrSP(Instruction *instr) const
Definition: disasm-arm64.h:62
int SubstituteLiteralField(Instruction *instr, const char *format)
bool RmIsZROrSP(Instruction *instr) const
Definition: disasm-arm64.h:58
int SubstituteConditionField(Instruction *instr, const char *format)
int SubstituteBitfieldImmediateField(Instruction *instr, const char *format)
int SubstituteImmediateField(Instruction *instr, const char *format)
int SubstitutePCRelAddressField(Instruction *instr, const char *format)
int SubstituteShiftField(Instruction *instr, const char *format)
int SubstituteRegisterField(Instruction *instr, const char *format)
int SubstituteLSRegOffsetField(Instruction *instr, const char *format)
int SubstituteBarrierField(Instruction *instr, const char *format)
void Substitute(Instruction *instr, const char *string)
int SubstitutePrefetchField(Instruction *instr, const char *format)
virtual void ProcessOutput(Instruction *instr)
virtual void ProcessOutput(Instruction *instr)
T * start() const
Definition: vector.h:47
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long mode(MIPS only)") DEFINE_BOOL(enable_always_align_csp
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be expose gc extension under the specified name show built in functions in stack traces use random jit cookie to mask large constants minimum length for automatic enable preparsing CPU profiler sampling interval in microseconds trace out of bounds accesses to external arrays default size of stack region v8 is allowed to maximum length of function source code printed in a stack trace min size of a semi the new space consists of two semi spaces print one trace line following each garbage collection do not print trace line after scavenger collection print cumulative GC statistics in only print modified registers Trace simulator debug messages Implied by trace sim abort randomize hashes to avoid predictable hash Fixed seed to use to hash property Print the time it takes to deserialize the snapshot A filename with extra code to be included in the A file to write the raw snapshot bytes A file to write the raw context snapshot bytes Write V8 startup blob file(mksnapshot only)") DEFINE_BOOL(profile_hydrogen_code_stub_compilation
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be NULL
enable harmony numeric enable harmony object literal extensions Optimize object Array shift
#define UNREACHABLE()
Definition: logging.h:30
#define DCHECK(condition)
Definition: logging.h:205
void USE(T)
Definition: macros.h:322
Definition: disasm.h:8
const unsigned kXRegSizeInBits
@ LoadStorePairNonTemporalMask
int SNPrintF(Vector< char > str, const char *format,...)
Definition: utils.cc:105
const unsigned kWRegSizeInBits
const unsigned kLoadLiteralScaleLog2
const Register pc
Condition NegateCondition(Condition cond)
Definition: constants-arm.h:86
T Abs(T a)
Definition: utils.h:153
const unsigned kZeroRegCode
const unsigned kNumberOfRegisters
const unsigned kInstructionSize
const unsigned kLinkRegCode
@ ConditionalCompareImmediateMask
const unsigned kInstructionSizeLog2
@ ConditionalCompareRegisterMask
@ UnconditionalBranchToRegisterMask
Debugger support for the V8 JavaScript engine.
Definition: accessors.cc:20