summaryrefslogtreecommitdiff
path: root/deps/v8/src/arm64/simulator-arm64.h
blob: d4901098ef298cacce5e9b95e3559ea1ddc1baa3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
// Copyright 2013 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_ARM64_SIMULATOR_ARM64_H_
#define V8_ARM64_SIMULATOR_ARM64_H_

#include <stdarg.h>
#include <vector>

#include "src/allocation.h"
#include "src/arm64/assembler-arm64.h"
#include "src/arm64/decoder-arm64.h"
#include "src/arm64/disasm-arm64.h"
#include "src/arm64/instrument-arm64.h"
#include "src/assembler.h"
#include "src/base/compiler-specific.h"
#include "src/globals.h"
#include "src/utils.h"

namespace v8 {
namespace internal {

#if !defined(USE_SIMULATOR)

// Running without a simulator on a native ARM64 platform.
// When running without a simulator we call the entry directly.
#define CALL_GENERATED_CODE(isolate, entry, p0, p1, p2, p3, p4) \
  (entry(p0, p1, p2, p3, p4))

typedef int (*arm64_regexp_matcher)(String* input,
                                    int64_t start_offset,
                                    const byte* input_start,
                                    const byte* input_end,
                                    int* output,
                                    int64_t output_size,
                                    Address stack_base,
                                    int64_t direct_call,
                                    void* return_address,
                                    Isolate* isolate);

// Call the generated regexp code directly. The code at the entry address
// should act as a function matching the type arm64_regexp_matcher.
// The ninth argument is a dummy that reserves the space used for
// the return address added by the ExitFrame in native calls.
#define CALL_GENERATED_REGEXP_CODE(isolate, entry, p0, p1, p2, p3, p4, p5, p6, \
                                   p7, p8)                                     \
  (FUNCTION_CAST<arm64_regexp_matcher>(entry)(p0, p1, p2, p3, p4, p5, p6, p7,  \
                                              NULL, p8))

// Running without a simulator there is nothing to do.
class SimulatorStack : public v8::internal::AllStatic {
 public:
  static uintptr_t JsLimitFromCLimit(v8::internal::Isolate* isolate,
                                     uintptr_t c_limit) {
    USE(isolate);
    return c_limit;
  }

  static uintptr_t RegisterCTryCatch(v8::internal::Isolate* isolate,
                                     uintptr_t try_catch_address) {
    USE(isolate);
    return try_catch_address;
  }

  static void UnregisterCTryCatch(v8::internal::Isolate* isolate) {
    USE(isolate);
  }
};

#else  // !defined(USE_SIMULATOR)


// The proper way to initialize a simulated system register (such as NZCV) is as
// follows:
//  SimSystemRegister nzcv = SimSystemRegister::DefaultValueFor(NZCV);
class SimSystemRegister {
 public:
  // The default constructor represents a register which has no writable bits.
  // It is not possible to set its value to anything other than 0.
  SimSystemRegister() : value_(0), write_ignore_mask_(0xffffffff) { }

  uint32_t RawValue() const {
    return value_;
  }

  void SetRawValue(uint32_t new_value) {
    value_ = (value_ & write_ignore_mask_) | (new_value & ~write_ignore_mask_);
  }

  uint32_t Bits(int msb, int lsb) const {
    return unsigned_bitextract_32(msb, lsb, value_);
  }

  int32_t SignedBits(int msb, int lsb) const {
    return signed_bitextract_32(msb, lsb, value_);
  }

  void SetBits(int msb, int lsb, uint32_t bits);

  // Default system register values.
  static SimSystemRegister DefaultValueFor(SystemRegister id);

#define DEFINE_GETTER(Name, HighBit, LowBit, Func, Type)                       \
  Type Name() const { return static_cast<Type>(Func(HighBit, LowBit)); }       \
  void Set##Name(Type bits) {                                                  \
    SetBits(HighBit, LowBit, static_cast<Type>(bits));                         \
  }
#define DEFINE_WRITE_IGNORE_MASK(Name, Mask)                                   \
  static const uint32_t Name##WriteIgnoreMask = ~static_cast<uint32_t>(Mask);
  SYSTEM_REGISTER_FIELDS_LIST(DEFINE_GETTER, DEFINE_WRITE_IGNORE_MASK)
#undef DEFINE_ZERO_BITS
#undef DEFINE_GETTER

 protected:
  // Most system registers only implement a few of the bits in the word. Other
  // bits are "read-as-zero, write-ignored". The write_ignore_mask argument
  // describes the bits which are not modifiable.
  SimSystemRegister(uint32_t value, uint32_t write_ignore_mask)
      : value_(value), write_ignore_mask_(write_ignore_mask) { }

  uint32_t value_;
  uint32_t write_ignore_mask_;
};


// Represent a register (r0-r31, v0-v31).
class SimRegisterBase {
 public:
  template<typename T>
  void Set(T new_value) {
    value_ = 0;
    memcpy(&value_, &new_value, sizeof(T));
  }

  template<typename T>
  T Get() const {
    T result;
    memcpy(&result, &value_, sizeof(T));
    return result;
  }

 protected:
  int64_t value_;
};


typedef SimRegisterBase SimRegister;      // r0-r31
typedef SimRegisterBase SimFPRegister;    // v0-v31


class Simulator : public DecoderVisitor {
 public:
  static void FlushICache(base::HashMap* i_cache, void* start, size_t size) {
    USE(i_cache);
    USE(start);
    USE(size);
  }

  explicit Simulator(Decoder<DispatchingDecoderVisitor>* decoder,
                     Isolate* isolate = NULL,
                     FILE* stream = stderr);
  Simulator();
  ~Simulator();

  // System functions.

  static void Initialize(Isolate* isolate);

  static void TearDown(base::HashMap* i_cache, Redirection* first);

  static Simulator* current(v8::internal::Isolate* isolate);

  class CallArgument;

  // Call an arbitrary function taking an arbitrary number of arguments. The
  // varargs list must be a set of arguments with type CallArgument, and
  // terminated by CallArgument::End().
  void CallVoid(byte* entry, CallArgument* args);

  // Like CallVoid, but expect a return value.
  int64_t CallInt64(byte* entry, CallArgument* args);
  double CallDouble(byte* entry, CallArgument* args);

  // V8 calls into generated JS code with 5 parameters and into
  // generated RegExp code with 10 parameters. These are convenience functions,
  // which set up the simulator state and grab the result on return.
  int64_t CallJS(byte* entry,
                 Object* new_target,
                 Object* target,
                 Object* revc,
                 int64_t argc,
                 Object*** argv);
  int64_t CallRegExp(byte* entry,
                     String* input,
                     int64_t start_offset,
                     const byte* input_start,
                     const byte* input_end,
                     int* output,
                     int64_t output_size,
                     Address stack_base,
                     int64_t direct_call,
                     void* return_address,
                     Isolate* isolate);

  // A wrapper class that stores an argument for one of the above Call
  // functions.
  //
  // Only arguments up to 64 bits in size are supported.
  class CallArgument {
   public:
    template<typename T>
    explicit CallArgument(T argument) {
      bits_ = 0;
      DCHECK(sizeof(argument) <= sizeof(bits_));
      memcpy(&bits_, &argument, sizeof(argument));
      type_ = X_ARG;
    }

    explicit CallArgument(double argument) {
      DCHECK(sizeof(argument) == sizeof(bits_));
      memcpy(&bits_, &argument, sizeof(argument));
      type_ = D_ARG;
    }

    explicit CallArgument(float argument) {
      // TODO(all): CallArgument(float) is untested, remove this check once
      //            tested.
      UNIMPLEMENTED();
      // Make the D register a NaN to try to trap errors if the callee expects a
      // double. If it expects a float, the callee should ignore the top word.
      DCHECK(sizeof(kFP64SignallingNaN) == sizeof(bits_));
      memcpy(&bits_, &kFP64SignallingNaN, sizeof(kFP64SignallingNaN));
      // Write the float payload to the S register.
      DCHECK(sizeof(argument) <= sizeof(bits_));
      memcpy(&bits_, &argument, sizeof(argument));
      type_ = D_ARG;
    }

    // This indicates the end of the arguments list, so that CallArgument
    // objects can be passed into varargs functions.
    static CallArgument End() { return CallArgument(); }

    int64_t bits() const { return bits_; }
    bool IsEnd() const { return type_ == NO_ARG; }
    bool IsX() const { return type_ == X_ARG; }
    bool IsD() const { return type_ == D_ARG; }

   private:
    enum CallArgumentType { X_ARG, D_ARG, NO_ARG };

    // All arguments are aligned to at least 64 bits and we don't support
    // passing bigger arguments, so the payload size can be fixed at 64 bits.
    int64_t bits_;
    CallArgumentType type_;

    CallArgument() { type_ = NO_ARG; }
  };


  // Start the debugging command line.
  void Debug();

  bool GetValue(const char* desc, int64_t* value);

  bool PrintValue(const char* desc);

  // Push an address onto the JS stack.
  uintptr_t PushAddress(uintptr_t address);

  // Pop an address from the JS stack.
  uintptr_t PopAddress();

  // Accessor to the internal simulator stack area.
  uintptr_t StackLimit(uintptr_t c_limit) const;

  void ResetState();

  // Runtime call support.
  static void* RedirectExternalReference(Isolate* isolate,
                                         void* external_function,
                                         ExternalReference::Type type);
  void DoRuntimeCall(Instruction* instr);

  // Run the simulator.
  static const Instruction* kEndOfSimAddress;
  void DecodeInstruction();
  void Run();
  void RunFrom(Instruction* start);

  // Simulation helpers.
  template <typename T>
  void set_pc(T new_pc) {
    DCHECK(sizeof(T) == sizeof(pc_));
    memcpy(&pc_, &new_pc, sizeof(T));
    pc_modified_ = true;
  }
  Instruction* pc() { return pc_; }

  void increment_pc() {
    if (!pc_modified_) {
      pc_ = pc_->following();
    }

    pc_modified_ = false;
  }

  virtual void Decode(Instruction* instr) {
    decoder_->Decode(instr);
  }

  void ExecuteInstruction() {
    DCHECK(IsAligned(reinterpret_cast<uintptr_t>(pc_), kInstructionSize));
    CheckBreakNext();
    Decode(pc_);
    increment_pc();
    CheckBreakpoints();
  }

  // Declare all Visitor functions.
  #define DECLARE(A)  void Visit##A(Instruction* instr);
  VISITOR_LIST(DECLARE)
  #undef DECLARE

  bool IsZeroRegister(unsigned code, Reg31Mode r31mode) const {
    return ((code == 31) && (r31mode == Reg31IsZeroRegister));
  }

  // Register accessors.
  // Return 'size' bits of the value of an integer register, as the specified
  // type. The value is zero-extended to fill the result.
  //
  template<typename T>
  T reg(unsigned code, Reg31Mode r31mode = Reg31IsZeroRegister) const {
    DCHECK(code < kNumberOfRegisters);
    if (IsZeroRegister(code, r31mode)) {
      return 0;
    }
    return registers_[code].Get<T>();
  }

  // Common specialized accessors for the reg() template.
  int32_t wreg(unsigned code, Reg31Mode r31mode = Reg31IsZeroRegister) const {
    return reg<int32_t>(code, r31mode);
  }

  int64_t xreg(unsigned code, Reg31Mode r31mode = Reg31IsZeroRegister) const {
    return reg<int64_t>(code, r31mode);
  }

  // Write 'value' into an integer register. The value is zero-extended. This
  // behaviour matches AArch64 register writes.
  template<typename T>
  void set_reg(unsigned code, T value,
               Reg31Mode r31mode = Reg31IsZeroRegister) {
    set_reg_no_log(code, value, r31mode);
    LogRegister(code, r31mode);
  }

  // Common specialized accessors for the set_reg() template.
  void set_wreg(unsigned code, int32_t value,
                Reg31Mode r31mode = Reg31IsZeroRegister) {
    set_reg(code, value, r31mode);
  }

  void set_xreg(unsigned code, int64_t value,
                Reg31Mode r31mode = Reg31IsZeroRegister) {
    set_reg(code, value, r31mode);
  }

  // As above, but don't automatically log the register update.
  template <typename T>
  void set_reg_no_log(unsigned code, T value,
                      Reg31Mode r31mode = Reg31IsZeroRegister) {
    DCHECK(code < kNumberOfRegisters);
    if (!IsZeroRegister(code, r31mode)) {
      registers_[code].Set(value);
    }
  }

  void set_wreg_no_log(unsigned code, int32_t value,
                       Reg31Mode r31mode = Reg31IsZeroRegister) {
    set_reg_no_log(code, value, r31mode);
  }

  void set_xreg_no_log(unsigned code, int64_t value,
                       Reg31Mode r31mode = Reg31IsZeroRegister) {
    set_reg_no_log(code, value, r31mode);
  }

  // Commonly-used special cases.
  template<typename T>
  void set_lr(T value) {
    DCHECK(sizeof(T) == kPointerSize);
    set_reg(kLinkRegCode, value);
  }

  template<typename T>
  void set_sp(T value) {
    DCHECK(sizeof(T) == kPointerSize);
    set_reg(31, value, Reg31IsStackPointer);
  }

  int64_t sp() { return xreg(31, Reg31IsStackPointer); }
  int64_t jssp() { return xreg(kJSSPCode, Reg31IsStackPointer); }
  int64_t fp() {
      return xreg(kFramePointerRegCode, Reg31IsStackPointer);
  }
  Instruction* lr() { return reg<Instruction*>(kLinkRegCode); }

  Address get_sp() const { return reg<Address>(31, Reg31IsStackPointer); }

  template<typename T>
  T fpreg(unsigned code) const {
    DCHECK(code < kNumberOfRegisters);
    return fpregisters_[code].Get<T>();
  }

  // Common specialized accessors for the fpreg() template.
  float sreg(unsigned code) const {
    return fpreg<float>(code);
  }

  uint32_t sreg_bits(unsigned code) const {
    return fpreg<uint32_t>(code);
  }

  double dreg(unsigned code) const {
    return fpreg<double>(code);
  }

  uint64_t dreg_bits(unsigned code) const {
    return fpreg<uint64_t>(code);
  }

  double fpreg(unsigned size, unsigned code) const {
    switch (size) {
      case kSRegSizeInBits: return sreg(code);
      case kDRegSizeInBits: return dreg(code);
      default:
        UNREACHABLE();
        return 0.0;
    }
  }

  // Write 'value' into a floating-point register. The value is zero-extended.
  // This behaviour matches AArch64 register writes.
  template<typename T>
  void set_fpreg(unsigned code, T value) {
    set_fpreg_no_log(code, value);

    if (sizeof(value) <= kSRegSize) {
      LogFPRegister(code, kPrintSRegValue);
    } else {
      LogFPRegister(code, kPrintDRegValue);
    }
  }

  // Common specialized accessors for the set_fpreg() template.
  void set_sreg(unsigned code, float value) {
    set_fpreg(code, value);
  }

  void set_sreg_bits(unsigned code, uint32_t value) {
    set_fpreg(code, value);
  }

  void set_dreg(unsigned code, double value) {
    set_fpreg(code, value);
  }

  void set_dreg_bits(unsigned code, uint64_t value) {
    set_fpreg(code, value);
  }

  // As above, but don't automatically log the register update.
  template <typename T>
  void set_fpreg_no_log(unsigned code, T value) {
    DCHECK((sizeof(value) == kDRegSize) || (sizeof(value) == kSRegSize));
    DCHECK(code < kNumberOfFPRegisters);
    fpregisters_[code].Set(value);
  }

  void set_sreg_no_log(unsigned code, float value) {
    set_fpreg_no_log(code, value);
  }

  void set_dreg_no_log(unsigned code, double value) {
    set_fpreg_no_log(code, value);
  }

  SimSystemRegister& nzcv() { return nzcv_; }
  SimSystemRegister& fpcr() { return fpcr_; }

  // Debug helpers

  // Simulator breakpoints.
  struct Breakpoint {
    Instruction* location;
    bool enabled;
  };
  std::vector<Breakpoint> breakpoints_;
  void SetBreakpoint(Instruction* breakpoint);
  void ListBreakpoints();
  void CheckBreakpoints();

  // Helpers for the 'next' command.
  // When this is set, the Simulator will insert a breakpoint after the next BL
  // instruction it meets.
  bool break_on_next_;
  // Check if the Simulator should insert a break after the current instruction
  // for the 'next' command.
  void CheckBreakNext();

  // Disassemble instruction at the given address.
  void PrintInstructionsAt(Instruction* pc, uint64_t count);

  // Print all registers of the specified types.
  void PrintRegisters();
  void PrintFPRegisters();
  void PrintSystemRegisters();

  // Like Print* (above), but respect log_parameters().
  void LogSystemRegisters() {
    if (log_parameters() & LOG_SYS_REGS) PrintSystemRegisters();
  }
  void LogRegisters() {
    if (log_parameters() & LOG_REGS) PrintRegisters();
  }
  void LogFPRegisters() {
    if (log_parameters() & LOG_FP_REGS) PrintFPRegisters();
  }

  // Specify relevant register sizes, for PrintFPRegister.
  //
  // These values are bit masks; they can be combined in case multiple views of
  // a machine register are interesting.
  enum PrintFPRegisterSizes {
    kPrintDRegValue = 1 << kDRegSize,
    kPrintSRegValue = 1 << kSRegSize,
    kPrintAllFPRegValues = kPrintDRegValue | kPrintSRegValue
  };

  // Print individual register values (after update).
  void PrintRegister(unsigned code, Reg31Mode r31mode = Reg31IsStackPointer);
  void PrintFPRegister(unsigned code,
                       PrintFPRegisterSizes sizes = kPrintAllFPRegValues);
  void PrintSystemRegister(SystemRegister id);

  // Like Print* (above), but respect log_parameters().
  void LogRegister(unsigned code, Reg31Mode r31mode = Reg31IsStackPointer) {
    if (log_parameters() & LOG_REGS) PrintRegister(code, r31mode);
  }
  void LogFPRegister(unsigned code,
                     PrintFPRegisterSizes sizes = kPrintAllFPRegValues) {
    if (log_parameters() & LOG_FP_REGS) PrintFPRegister(code, sizes);
  }
  void LogSystemRegister(SystemRegister id) {
    if (log_parameters() & LOG_SYS_REGS) PrintSystemRegister(id);
  }

  // Print memory accesses.
  void PrintRead(uintptr_t address, size_t size, unsigned reg_code);
  void PrintReadFP(uintptr_t address, size_t size, unsigned reg_code);
  void PrintWrite(uintptr_t address, size_t size, unsigned reg_code);
  void PrintWriteFP(uintptr_t address, size_t size, unsigned reg_code);

  // Like Print* (above), but respect log_parameters().
  void LogRead(uintptr_t address, size_t size, unsigned reg_code) {
    if (log_parameters() & LOG_REGS) PrintRead(address, size, reg_code);
  }
  void LogReadFP(uintptr_t address, size_t size, unsigned reg_code) {
    if (log_parameters() & LOG_FP_REGS) PrintReadFP(address, size, reg_code);
  }
  void LogWrite(uintptr_t address, size_t size, unsigned reg_code) {
    if (log_parameters() & LOG_WRITE) PrintWrite(address, size, reg_code);
  }
  void LogWriteFP(uintptr_t address, size_t size, unsigned reg_code) {
    if (log_parameters() & LOG_WRITE) PrintWriteFP(address, size, reg_code);
  }

  int log_parameters() { return log_parameters_; }
  void set_log_parameters(int new_parameters) {
    log_parameters_ = new_parameters;
    if (!decoder_) {
      if (new_parameters & LOG_DISASM) {
        PrintF("Run --debug-sim to dynamically turn on disassembler\n");
      }
      return;
    }
    if (new_parameters & LOG_DISASM) {
      decoder_->InsertVisitorBefore(print_disasm_, this);
    } else {
      decoder_->RemoveVisitor(print_disasm_);
    }
  }

  static inline const char* WRegNameForCode(unsigned code,
      Reg31Mode mode = Reg31IsZeroRegister);
  static inline const char* XRegNameForCode(unsigned code,
      Reg31Mode mode = Reg31IsZeroRegister);
  static inline const char* SRegNameForCode(unsigned code);
  static inline const char* DRegNameForCode(unsigned code);
  static inline const char* VRegNameForCode(unsigned code);
  static inline int CodeFromName(const char* name);

 protected:
  // Simulation helpers ------------------------------------
  bool ConditionPassed(Condition cond) {
    SimSystemRegister& flags = nzcv();
    switch (cond) {
      case eq:
        return flags.Z();
      case ne:
        return !flags.Z();
      case hs:
        return flags.C();
      case lo:
        return !flags.C();
      case mi:
        return flags.N();
      case pl:
        return !flags.N();
      case vs:
        return flags.V();
      case vc:
        return !flags.V();
      case hi:
        return flags.C() && !flags.Z();
      case ls:
        return !(flags.C() && !flags.Z());
      case ge:
        return flags.N() == flags.V();
      case lt:
        return flags.N() != flags.V();
      case gt:
        return !flags.Z() && (flags.N() == flags.V());
      case le:
        return !(!flags.Z() && (flags.N() == flags.V()));
      case nv:  // Fall through.
      case al:
        return true;
      default:
        UNREACHABLE();
        return false;
    }
  }

  bool ConditionFailed(Condition cond) {
    return !ConditionPassed(cond);
  }

  template<typename T>
  void AddSubHelper(Instruction* instr, T op2);
  template <typename T>
  T AddWithCarry(bool set_flags, T left, T right, int carry_in = 0);
  template<typename T>
  void AddSubWithCarry(Instruction* instr);
  template<typename T>
  void LogicalHelper(Instruction* instr, T op2);
  template<typename T>
  void ConditionalCompareHelper(Instruction* instr, T op2);
  void LoadStoreHelper(Instruction* instr,
                       int64_t offset,
                       AddrMode addrmode);
  void LoadStorePairHelper(Instruction* instr, AddrMode addrmode);
  uintptr_t LoadStoreAddress(unsigned addr_reg, int64_t offset,
                             AddrMode addrmode);
  void LoadStoreWriteBack(unsigned addr_reg,
                          int64_t offset,
                          AddrMode addrmode);
  void CheckMemoryAccess(uintptr_t address, uintptr_t stack);

  // Memory read helpers.
  template <typename T, typename A>
  T MemoryRead(A address) {
    T value;
    STATIC_ASSERT((sizeof(value) == 1) || (sizeof(value) == 2) ||
                  (sizeof(value) == 4) || (sizeof(value) == 8));
    memcpy(&value, reinterpret_cast<const void*>(address), sizeof(value));
    return value;
  }

  // Memory write helpers.
  template <typename T, typename A>
  void MemoryWrite(A address, T value) {
    STATIC_ASSERT((sizeof(value) == 1) || (sizeof(value) == 2) ||
                  (sizeof(value) == 4) || (sizeof(value) == 8));
    memcpy(reinterpret_cast<void*>(address), &value, sizeof(value));
  }

  template <typename T>
  T ShiftOperand(T value,
                 Shift shift_type,
                 unsigned amount);
  template <typename T>
  T ExtendValue(T value,
                Extend extend_type,
                unsigned left_shift = 0);
  template <typename T>
  void Extract(Instruction* instr);
  template <typename T>
  void DataProcessing2Source(Instruction* instr);
  template <typename T>
  void BitfieldHelper(Instruction* instr);

  template <typename T>
  T FPDefaultNaN() const;

  void FPCompare(double val0, double val1);
  double FPRoundInt(double value, FPRounding round_mode);
  double FPToDouble(float value);
  float FPToFloat(double value, FPRounding round_mode);
  double FixedToDouble(int64_t src, int fbits, FPRounding round_mode);
  double UFixedToDouble(uint64_t src, int fbits, FPRounding round_mode);
  float FixedToFloat(int64_t src, int fbits, FPRounding round_mode);
  float UFixedToFloat(uint64_t src, int fbits, FPRounding round_mode);
  int32_t FPToInt32(double value, FPRounding rmode);
  int64_t FPToInt64(double value, FPRounding rmode);
  uint32_t FPToUInt32(double value, FPRounding rmode);
  uint64_t FPToUInt64(double value, FPRounding rmode);

  template <typename T>
  T FPAdd(T op1, T op2);

  template <typename T>
  T FPDiv(T op1, T op2);

  template <typename T>
  T FPMax(T a, T b);

  template <typename T>
  T FPMaxNM(T a, T b);

  template <typename T>
  T FPMin(T a, T b);

  template <typename T>
  T FPMinNM(T a, T b);

  template <typename T>
  T FPMul(T op1, T op2);

  template <typename T>
  T FPMulAdd(T a, T op1, T op2);

  template <typename T>
  T FPSqrt(T op);

  template <typename T>
  T FPSub(T op1, T op2);

  // Standard NaN processing.
  template <typename T>
  T FPProcessNaN(T op);

  bool FPProcessNaNs(Instruction* instr);

  template <typename T>
  T FPProcessNaNs(T op1, T op2);

  template <typename T>
  T FPProcessNaNs3(T op1, T op2, T op3);

  void CheckStackAlignment();

  inline void CheckPCSComplianceAndRun();

#ifdef DEBUG
  // Corruption values should have their least significant byte cleared to
  // allow the code of the register being corrupted to be inserted.
  static const uint64_t kCallerSavedRegisterCorruptionValue =
      0xca11edc0de000000UL;
  // This value is a NaN in both 32-bit and 64-bit FP.
  static const uint64_t kCallerSavedFPRegisterCorruptionValue =
      0x7ff000007f801000UL;
  // This value is a mix of 32/64-bits NaN and "verbose" immediate.
  static const uint64_t kDefaultCPURegisterCorruptionValue =
      0x7ffbad007f8bad00UL;

  void CorruptRegisters(CPURegList* list,
                        uint64_t value = kDefaultCPURegisterCorruptionValue);
  void CorruptAllCallerSavedCPURegisters();
#endif

  // Pseudo Printf instruction
  void DoPrintf(Instruction* instr);

  // Processor state ---------------------------------------

  // Output stream.
  FILE* stream_;
  PrintDisassembler* print_disasm_;
  void PRINTF_FORMAT(2, 3) TraceSim(const char* format, ...);

  // Instrumentation.
  Instrument* instrument_;

  // General purpose registers. Register 31 is the stack pointer.
  SimRegister registers_[kNumberOfRegisters];

  // Floating point registers
  SimFPRegister fpregisters_[kNumberOfFPRegisters];

  // Processor state
  // bits[31, 27]: Condition flags N, Z, C, and V.
  //               (Negative, Zero, Carry, Overflow)
  SimSystemRegister nzcv_;

  // Floating-Point Control Register
  SimSystemRegister fpcr_;

  // Only a subset of FPCR features are supported by the simulator. This helper
  // checks that the FPCR settings are supported.
  //
  // This is checked when floating-point instructions are executed, not when
  // FPCR is set. This allows generated code to modify FPCR for external
  // functions, or to save and restore it when entering and leaving generated
  // code.
  void AssertSupportedFPCR() {
    DCHECK(fpcr().FZ() == 0);             // No flush-to-zero support.
    DCHECK(fpcr().RMode() == FPTieEven);  // Ties-to-even rounding only.

    // The simulator does not support half-precision operations so fpcr().AHP()
    // is irrelevant, and is not checked here.
  }

  template <typename T>
  static int CalcNFlag(T result) {
    return (result >> (sizeof(T) * 8 - 1)) & 1;
  }

  static int CalcZFlag(uint64_t result) {
    return result == 0;
  }

  static const uint32_t kConditionFlagsMask = 0xf0000000;

  // Stack
  uintptr_t stack_;
  static const size_t stack_protection_size_ = KB;
  size_t stack_size_;
  uintptr_t stack_limit_;

  Decoder<DispatchingDecoderVisitor>* decoder_;
  Decoder<DispatchingDecoderVisitor>* disassembler_decoder_;

  // Indicates if the pc has been modified by the instruction and should not be
  // automatically incremented.
  bool pc_modified_;
  Instruction* pc_;

  static const char* xreg_names[];
  static const char* wreg_names[];
  static const char* sreg_names[];
  static const char* dreg_names[];
  static const char* vreg_names[];

  // Debugger input.
  void set_last_debugger_input(char* input) {
    DeleteArray(last_debugger_input_);
    last_debugger_input_ = input;
  }
  char* last_debugger_input() { return last_debugger_input_; }
  char* last_debugger_input_;

 private:
  void Init(FILE* stream);

  int  log_parameters_;
  Isolate* isolate_;
};


// When running with the simulator transition into simulated execution at this
// point.
#define CALL_GENERATED_CODE(isolate, entry, p0, p1, p2, p3, p4)  \
  reinterpret_cast<Object*>(Simulator::current(isolate)->CallJS( \
      FUNCTION_ADDR(entry), p0, p1, p2, p3, p4))

#define CALL_GENERATED_REGEXP_CODE(isolate, entry, p0, p1, p2, p3, p4, p5, p6, \
                                   p7, p8)                                     \
  static_cast<int>(Simulator::current(isolate)->CallRegExp(                    \
      entry, p0, p1, p2, p3, p4, p5, p6, p7, NULL, p8))


// The simulator has its own stack. Thus it has a different stack limit from
// the C-based native code.  The JS-based limit normally points near the end of
// the simulator stack.  When the C-based limit is exhausted we reflect that by
// lowering the JS-based limit as well, to make stack checks trigger.
class SimulatorStack : public v8::internal::AllStatic {
 public:
  static uintptr_t JsLimitFromCLimit(v8::internal::Isolate* isolate,
                                            uintptr_t c_limit) {
    return Simulator::current(isolate)->StackLimit(c_limit);
  }

  static uintptr_t RegisterCTryCatch(v8::internal::Isolate* isolate,
                                     uintptr_t try_catch_address) {
    Simulator* sim = Simulator::current(isolate);
    return sim->PushAddress(try_catch_address);
  }

  static void UnregisterCTryCatch(v8::internal::Isolate* isolate) {
    Simulator::current(isolate)->PopAddress();
  }
};

#endif  // !defined(USE_SIMULATOR)

}  // namespace internal
}  // namespace v8

#endif  // V8_ARM64_SIMULATOR_ARM64_H_