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