The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / src / arm / simulator-arm.h @ f230a1cf

History | View | Annotate | Download (16.7 KB)

1
// Copyright 2012 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

    
29
// Declares a Simulator for ARM instructions if we are not generating a native
30
// ARM binary. This Simulator allows us to run and debug ARM code generation on
31
// regular desktop machines.
32
// V8 calls into generated code by "calling" the CALL_GENERATED_CODE macro,
33
// which will start execution in the Simulator or forwards to the real entry
34
// on a ARM HW platform.
35

    
36
#ifndef V8_ARM_SIMULATOR_ARM_H_
37
#define V8_ARM_SIMULATOR_ARM_H_
38

    
39
#include "allocation.h"
40

    
41
#if !defined(USE_SIMULATOR)
42
// Running without a simulator on a native arm platform.
43

    
44
namespace v8 {
45
namespace internal {
46

    
47
// When running without a simulator we call the entry directly.
48
#define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \
49
  (entry(p0, p1, p2, p3, p4))
50

    
51
typedef int (*arm_regexp_matcher)(String*, int, const byte*, const byte*,
52
                                  void*, int*, int, Address, int, Isolate*);
53

    
54

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

    
63
#define TRY_CATCH_FROM_ADDRESS(try_catch_address) \
64
  reinterpret_cast<TryCatch*>(try_catch_address)
65

    
66
// The stack limit beyond which we will throw stack overflow errors in
67
// generated code. Because generated code on arm uses the C stack, we
68
// just use the C stack limit.
69
class SimulatorStack : public v8::internal::AllStatic {
70
 public:
71
  static inline uintptr_t JsLimitFromCLimit(v8::internal::Isolate* isolate,
72
                                            uintptr_t c_limit) {
73
    USE(isolate);
74
    return c_limit;
75
  }
76

    
77
  static inline uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) {
78
    return try_catch_address;
79
  }
80

    
81
  static inline void UnregisterCTryCatch() { }
82
};
83

    
84
} }  // namespace v8::internal
85

    
86
#else  // !defined(USE_SIMULATOR)
87
// Running with a simulator.
88

    
89
#include "constants-arm.h"
90
#include "hashmap.h"
91
#include "assembler.h"
92

    
93
namespace v8 {
94
namespace internal {
95

    
96
class CachePage {
97
 public:
98
  static const int LINE_VALID = 0;
99
  static const int LINE_INVALID = 1;
100

    
101
  static const int kPageShift = 12;
102
  static const int kPageSize = 1 << kPageShift;
103
  static const int kPageMask = kPageSize - 1;
104
  static const int kLineShift = 2;  // The cache line is only 4 bytes right now.
105
  static const int kLineLength = 1 << kLineShift;
106
  static const int kLineMask = kLineLength - 1;
107

    
108
  CachePage() {
109
    memset(&validity_map_, LINE_INVALID, sizeof(validity_map_));
110
  }
111

    
112
  char* ValidityByte(int offset) {
113
    return &validity_map_[offset >> kLineShift];
114
  }
115

    
116
  char* CachedData(int offset) {
117
    return &data_[offset];
118
  }
119

    
120
 private:
121
  char data_[kPageSize];   // The cached data.
122
  static const int kValidityMapSize = kPageSize >> kLineShift;
123
  char validity_map_[kValidityMapSize];  // One byte per line.
124
};
125

    
126

    
127
class Simulator {
128
 public:
129
  friend class ArmDebugger;
130
  enum Register {
131
    no_reg = -1,
132
    r0 = 0, r1, r2, r3, r4, r5, r6, r7,
133
    r8, r9, r10, r11, r12, r13, r14, r15,
134
    num_registers,
135
    sp = 13,
136
    lr = 14,
137
    pc = 15,
138
    s0 = 0, s1, s2, s3, s4, s5, s6, s7,
139
    s8, s9, s10, s11, s12, s13, s14, s15,
140
    s16, s17, s18, s19, s20, s21, s22, s23,
141
    s24, s25, s26, s27, s28, s29, s30, s31,
142
    num_s_registers = 32,
143
    d0 = 0, d1, d2, d3, d4, d5, d6, d7,
144
    d8, d9, d10, d11, d12, d13, d14, d15,
145
    d16, d17, d18, d19, d20, d21, d22, d23,
146
    d24, d25, d26, d27, d28, d29, d30, d31,
147
    num_d_registers = 32,
148
    q0 = 0, q1, q2, q3, q4, q5, q6, q7,
149
    q8, q9, q10, q11, q12, q13, q14, q15,
150
    num_q_registers = 16
151
  };
152

    
153
  explicit Simulator(Isolate* isolate);
154
  ~Simulator();
155

    
156
  // The currently executing Simulator instance. Potentially there can be one
157
  // for each native thread.
158
  static Simulator* current(v8::internal::Isolate* isolate);
159

    
160
  // Accessors for register state. Reading the pc value adheres to the ARM
161
  // architecture specification and is off by a 8 from the currently executing
162
  // instruction.
163
  void set_register(int reg, int32_t value);
164
  int32_t get_register(int reg) const;
165
  double get_double_from_register_pair(int reg);
166
  void set_register_pair_from_double(int reg, double* value);
167
  void set_dw_register(int dreg, const int* dbl);
168

    
169
  // Support for VFP.
170
  void get_d_register(int dreg, uint64_t* value);
171
  void set_d_register(int dreg, const uint64_t* value);
172
  void get_d_register(int dreg, uint32_t* value);
173
  void set_d_register(int dreg, const uint32_t* value);
174
  void get_q_register(int qreg, uint64_t* value);
175
  void set_q_register(int qreg, const uint64_t* value);
176
  void get_q_register(int qreg, uint32_t* value);
177
  void set_q_register(int qreg, const uint32_t* value);
178

    
179
  void set_s_register(int reg, unsigned int value);
180
  unsigned int get_s_register(int reg) const;
181

    
182
  void set_d_register_from_double(int dreg, const double& dbl) {
183
    SetVFPRegister<double, 2>(dreg, dbl);
184
  }
185

    
186
  double get_double_from_d_register(int dreg) {
187
    return GetFromVFPRegister<double, 2>(dreg);
188
  }
189

    
190
  void set_s_register_from_float(int sreg, const float flt) {
191
    SetVFPRegister<float, 1>(sreg, flt);
192
  }
193

    
194
  float get_float_from_s_register(int sreg) {
195
    return GetFromVFPRegister<float, 1>(sreg);
196
  }
197

    
198
  void set_s_register_from_sinteger(int sreg, const int sint) {
199
    SetVFPRegister<int, 1>(sreg, sint);
200
  }
201

    
202
  int get_sinteger_from_s_register(int sreg) {
203
    return GetFromVFPRegister<int, 1>(sreg);
204
  }
205

    
206
  // Special case of set_register and get_register to access the raw PC value.
207
  void set_pc(int32_t value);
208
  int32_t get_pc() const;
209

    
210
  // Accessor to the internal simulator stack area.
211
  uintptr_t StackLimit() const;
212

    
213
  // Executes ARM instructions until the PC reaches end_sim_pc.
214
  void Execute();
215

    
216
  // Call on program start.
217
  static void Initialize(Isolate* isolate);
218

    
219
  // V8 generally calls into generated JS code with 5 parameters and into
220
  // generated RegExp code with 7 parameters. This is a convenience function,
221
  // which sets up the simulator state and grabs the result on return.
222
  int32_t Call(byte* entry, int argument_count, ...);
223
  // Alternative: call a 2-argument double function.
224
  void CallFP(byte* entry, double d0, double d1);
225
  int32_t CallFPReturnsInt(byte* entry, double d0, double d1);
226
  double CallFPReturnsDouble(byte* entry, double d0, double d1);
227

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

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

    
234
  // Debugger input.
235
  void set_last_debugger_input(char* input);
236
  char* last_debugger_input() { return last_debugger_input_; }
237

    
238
  // ICache checking.
239
  static void FlushICache(v8::internal::HashMap* i_cache, void* start,
240
                          size_t size);
241

    
242
  // Returns true if pc register contains one of the 'special_values' defined
243
  // below (bad_lr, end_sim_pc).
244
  bool has_bad_pc() const;
245

    
246
  // EABI variant for double arguments in use.
247
  bool use_eabi_hardfloat() {
248
#if USE_EABI_HARDFLOAT
249
    return true;
250
#else
251
    return false;
252
#endif
253
  }
254

    
255
 private:
256
  enum special_values {
257
    // Known bad pc value to ensure that the simulator does not execute
258
    // without being properly setup.
259
    bad_lr = -1,
260
    // A pc value used to signal the simulator to stop execution.  Generally
261
    // the lr is set to this value on transition from native C code to
262
    // simulated execution, so that the simulator can "return" to the native
263
    // C code.
264
    end_sim_pc = -2
265
  };
266

    
267
  // Unsupported instructions use Format to print an error and stop execution.
268
  void Format(Instruction* instr, const char* format);
269

    
270
  // Checks if the current instruction should be executed based on its
271
  // condition bits.
272
  bool ConditionallyExecute(Instruction* instr);
273

    
274
  // Helper functions to set the conditional flags in the architecture state.
275
  void SetNZFlags(int32_t val);
276
  void SetCFlag(bool val);
277
  void SetVFlag(bool val);
278
  bool CarryFrom(int32_t left, int32_t right, int32_t carry = 0);
279
  bool BorrowFrom(int32_t left, int32_t right);
280
  bool OverflowFrom(int32_t alu_out,
281
                    int32_t left,
282
                    int32_t right,
283
                    bool addition);
284

    
285
  inline int GetCarry() {
286
    return c_flag_ ? 1 : 0;
287
  };
288

    
289
  // Support for VFP.
290
  void Compute_FPSCR_Flags(double val1, double val2);
291
  void Copy_FPSCR_to_APSR();
292
  inline double canonicalizeNaN(double value);
293

    
294
  // Helper functions to decode common "addressing" modes
295
  int32_t GetShiftRm(Instruction* instr, bool* carry_out);
296
  int32_t GetImm(Instruction* instr, bool* carry_out);
297
  int32_t ProcessPU(Instruction* instr,
298
                    int num_regs,
299
                    int operand_size,
300
                    intptr_t* start_address,
301
                    intptr_t* end_address);
302
  void HandleRList(Instruction* instr, bool load);
303
  void HandleVList(Instruction* inst);
304
  void SoftwareInterrupt(Instruction* instr);
305

    
306
  // Stop helper functions.
307
  inline bool isStopInstruction(Instruction* instr);
308
  inline bool isWatchedStop(uint32_t bkpt_code);
309
  inline bool isEnabledStop(uint32_t bkpt_code);
310
  inline void EnableStop(uint32_t bkpt_code);
311
  inline void DisableStop(uint32_t bkpt_code);
312
  inline void IncreaseStopCounter(uint32_t bkpt_code);
313
  void PrintStopInfo(uint32_t code);
314

    
315
  // Read and write memory.
316
  inline uint8_t ReadBU(int32_t addr);
317
  inline int8_t ReadB(int32_t addr);
318
  inline void WriteB(int32_t addr, uint8_t value);
319
  inline void WriteB(int32_t addr, int8_t value);
320

    
321
  inline uint16_t ReadHU(int32_t addr, Instruction* instr);
322
  inline int16_t ReadH(int32_t addr, Instruction* instr);
323
  // Note: Overloaded on the sign of the value.
324
  inline void WriteH(int32_t addr, uint16_t value, Instruction* instr);
325
  inline void WriteH(int32_t addr, int16_t value, Instruction* instr);
326

    
327
  inline int ReadW(int32_t addr, Instruction* instr);
328
  inline void WriteW(int32_t addr, int value, Instruction* instr);
329

    
330
  int32_t* ReadDW(int32_t addr);
331
  void WriteDW(int32_t addr, int32_t value1, int32_t value2);
332

    
333
  // Executing is handled based on the instruction type.
334
  // Both type 0 and type 1 rolled into one.
335
  void DecodeType01(Instruction* instr);
336
  void DecodeType2(Instruction* instr);
337
  void DecodeType3(Instruction* instr);
338
  void DecodeType4(Instruction* instr);
339
  void DecodeType5(Instruction* instr);
340
  void DecodeType6(Instruction* instr);
341
  void DecodeType7(Instruction* instr);
342

    
343
  // Support for VFP.
344
  void DecodeTypeVFP(Instruction* instr);
345
  void DecodeType6CoprocessorIns(Instruction* instr);
346
  void DecodeSpecialCondition(Instruction* instr);
347

    
348
  void DecodeVMOVBetweenCoreAndSinglePrecisionRegisters(Instruction* instr);
349
  void DecodeVCMP(Instruction* instr);
350
  void DecodeVCVTBetweenDoubleAndSingle(Instruction* instr);
351
  void DecodeVCVTBetweenFloatingPointAndInteger(Instruction* instr);
352

    
353
  // Executes one instruction.
354
  void InstructionDecode(Instruction* instr);
355

    
356
  // ICache.
357
  static void CheckICache(v8::internal::HashMap* i_cache, Instruction* instr);
358
  static void FlushOnePage(v8::internal::HashMap* i_cache, intptr_t start,
359
                           int size);
360
  static CachePage* GetCachePage(v8::internal::HashMap* i_cache, void* page);
361

    
362
  // Runtime call support.
363
  static void* RedirectExternalReference(
364
      void* external_function,
365
      v8::internal::ExternalReference::Type type);
366

    
367
  // Handle arguments and return value for runtime FP functions.
368
  void GetFpArgs(double* x, double* y, int32_t* z);
369
  void SetFpResult(const double& result);
370
  void TrashCallerSaveRegisters();
371

    
372
  template<class ReturnType, int register_size>
373
      ReturnType GetFromVFPRegister(int reg_index);
374

    
375
  template<class InputType, int register_size>
376
      void SetVFPRegister(int reg_index, const InputType& value);
377

    
378
  void CallInternal(byte* entry);
379

    
380
  // Architecture state.
381
  // Saturating instructions require a Q flag to indicate saturation.
382
  // There is currently no way to read the CPSR directly, and thus read the Q
383
  // flag, so this is left unimplemented.
384
  int32_t registers_[16];
385
  bool n_flag_;
386
  bool z_flag_;
387
  bool c_flag_;
388
  bool v_flag_;
389

    
390
  // VFP architecture state.
391
  unsigned int vfp_registers_[num_d_registers * 2];
392
  bool n_flag_FPSCR_;
393
  bool z_flag_FPSCR_;
394
  bool c_flag_FPSCR_;
395
  bool v_flag_FPSCR_;
396

    
397
  // VFP rounding mode. See ARM DDI 0406B Page A2-29.
398
  VFPRoundingMode FPSCR_rounding_mode_;
399
  bool FPSCR_default_NaN_mode_;
400

    
401
  // VFP FP exception flags architecture state.
402
  bool inv_op_vfp_flag_;
403
  bool div_zero_vfp_flag_;
404
  bool overflow_vfp_flag_;
405
  bool underflow_vfp_flag_;
406
  bool inexact_vfp_flag_;
407

    
408
  // Simulator support.
409
  char* stack_;
410
  bool pc_modified_;
411
  int icount_;
412

    
413
  // Debugger input.
414
  char* last_debugger_input_;
415

    
416
  // Icache simulation
417
  v8::internal::HashMap* i_cache_;
418

    
419
  // Registered breakpoints.
420
  Instruction* break_pc_;
421
  Instr break_instr_;
422

    
423
  v8::internal::Isolate* isolate_;
424

    
425
  // A stop is watched if its code is less than kNumOfWatchedStops.
426
  // Only watched stops support enabling/disabling and the counter feature.
427
  static const uint32_t kNumOfWatchedStops = 256;
428

    
429
  // Breakpoint is disabled if bit 31 is set.
430
  static const uint32_t kStopDisabledBit = 1 << 31;
431

    
432
  // A stop is enabled, meaning the simulator will stop when meeting the
433
  // instruction, if bit 31 of watched_stops_[code].count is unset.
434
  // The value watched_stops_[code].count & ~(1 << 31) indicates how many times
435
  // the breakpoint was hit or gone through.
436
  struct StopCountAndDesc {
437
    uint32_t count;
438
    char* desc;
439
  };
440
  StopCountAndDesc watched_stops_[kNumOfWatchedStops];
441
};
442

    
443

    
444
// When running with the simulator transition into simulated execution at this
445
// point.
446
#define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \
447
  reinterpret_cast<Object*>(Simulator::current(Isolate::Current())->Call( \
448
      FUNCTION_ADDR(entry), 5, p0, p1, p2, p3, p4))
449

    
450
#define CALL_GENERATED_FP_INT(entry, p0, p1) \
451
  Simulator::current(Isolate::Current())->CallFPReturnsInt( \
452
      FUNCTION_ADDR(entry), p0, p1)
453

    
454
#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7, p8) \
455
  Simulator::current(Isolate::Current())->Call( \
456
      entry, 10, p0, p1, p2, p3, NULL, p4, p5, p6, p7, p8)
457

    
458
#define TRY_CATCH_FROM_ADDRESS(try_catch_address)                              \
459
  try_catch_address == NULL ?                                                  \
460
      NULL : *(reinterpret_cast<TryCatch**>(try_catch_address))
461

    
462

    
463
// The simulator has its own stack. Thus it has a different stack limit from
464
// the C-based native code.  Setting the c_limit to indicate a very small
465
// stack cause stack overflow errors, since the simulator ignores the input.
466
// This is unlikely to be an issue in practice, though it might cause testing
467
// trouble down the line.
468
class SimulatorStack : public v8::internal::AllStatic {
469
 public:
470
  static inline uintptr_t JsLimitFromCLimit(v8::internal::Isolate* isolate,
471
                                            uintptr_t c_limit) {
472
    return Simulator::current(isolate)->StackLimit();
473
  }
474

    
475
  static inline uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) {
476
    Simulator* sim = Simulator::current(Isolate::Current());
477
    return sim->PushAddress(try_catch_address);
478
  }
479

    
480
  static inline void UnregisterCTryCatch() {
481
    Simulator::current(Isolate::Current())->PopAddress();
482
  }
483
};
484

    
485
} }  // namespace v8::internal
486

    
487
#endif  // !defined(USE_SIMULATOR)
488
#endif  // V8_ARM_SIMULATOR_ARM_H_