simulator-mips.h 15.2 KB
Newer Older
1
// Copyright 2011 the V8 project authors. All rights reserved.
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
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//     * Neither the name of Google Inc. nor the names of its
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


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

#ifndef V8_MIPS_SIMULATOR_MIPS_H_
#define V8_MIPS_SIMULATOR_MIPS_H_

#include "allocation.h"
40
#include "constants-mips.h"
41

42 43 44 45 46
#if !defined(USE_SIMULATOR)
// Running without a simulator on a native mips platform.

namespace v8 {
namespace internal {
47 48 49

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

typedef int (*mips_regexp_matcher)(String*, int, const byte*, const byte*,
53
                                   void*, int*, int, Address, int, Isolate*);
54

55 56 57 58 59

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

#define TRY_CATCH_FROM_ADDRESS(try_catch_address) \
  reinterpret_cast<TryCatch*>(try_catch_address)
66 67 68 69 70 71

// The stack limit beyond which we will throw stack overflow errors in
// generated code. Because generated code on mips uses the C stack, we
// just use the C stack limit.
class SimulatorStack : public v8::internal::AllStatic {
 public:
72 73
  static inline uintptr_t JsLimitFromCLimit(Isolate* isolate,
                                            uintptr_t c_limit) {
74 75 76 77 78 79 80 81 82 83
    return c_limit;
  }

  static inline uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) {
    return try_catch_address;
  }

  static inline void UnregisterCTryCatch() { }
};

84 85
} }  // namespace v8::internal

86 87 88 89 90 91 92 93 94 95
// Calculated the stack limit beyond which we will throw stack overflow errors.
// This macro must be called from a C++ method. It relies on being able to take
// the address of "this" to get a value on the current execution stack and then
// calculates the stack limit based on that value.
// NOTE: The check for overflow is not safe as there is no guarantee that the
// running thread has its stack in all memory up to address 0x00000000.
#define GENERATED_CODE_STACK_LIMIT(limit) \
  (reinterpret_cast<uintptr_t>(this) >= limit ? \
      reinterpret_cast<uintptr_t>(this) - limit : 0)

96 97
#else  // !defined(USE_SIMULATOR)
// Running with a simulator.
98

99
#include "hashmap.h"
100
#include "assembler.h"
101

102 103
namespace v8 {
namespace internal {
104

105 106
// -----------------------------------------------------------------------------
// Utility functions
107

108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
class CachePage {
 public:
  static const int LINE_VALID = 0;
  static const int LINE_INVALID = 1;

  static const int kPageShift = 12;
  static const int kPageSize = 1 << kPageShift;
  static const int kPageMask = kPageSize - 1;
  static const int kLineShift = 2;  // The cache line is only 4 bytes right now.
  static const int kLineLength = 1 << kLineShift;
  static const int kLineMask = kLineLength - 1;

  CachePage() {
    memset(&validity_map_, LINE_INVALID, sizeof(validity_map_));
  }
123

124 125 126
  char* ValidityByte(int offset) {
    return &validity_map_[offset >> kLineShift];
  }
127

128 129 130
  char* CachedData(int offset) {
    return &data_[offset];
  }
131

132 133 134 135 136
 private:
  char data_[kPageSize];   // The cached data.
  static const int kValidityMapSize = kPageSize >> kLineShift;
  char validity_map_[kValidityMapSize];  // One byte per line.
};
137 138 139

class Simulator {
 public:
140
  friend class MipsDebugger;
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156

  // Registers are declared in order. See SMRL chapter 2.
  enum Register {
    no_reg = -1,
    zero_reg = 0,
    at,
    v0, v1,
    a0, a1, a2, a3,
    t0, t1, t2, t3, t4, t5, t6, t7,
    s0, s1, s2, s3, s4, s5, s6, s7,
    t8, t9,
    k0, k1,
    gp,
    sp,
    s8,
    ra,
157
    // LO, HI, and pc.
158 159 160 161 162 163 164 165 166 167 168 169
    LO,
    HI,
    pc,   // pc must be the last register.
    kNumSimuRegisters,
    // aliases
    fp = s8
  };

  // Coprocessor registers.
  // Generated code will always use doubles. So we will only use even registers.
  enum FPURegister {
    f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11,
170
    f12, f13, f14, f15,   // f12 and f14 are arguments FPURegisters.
171 172 173 174 175
    f16, f17, f18, f19, f20, f21, f22, f23, f24, f25,
    f26, f27, f28, f29, f30, f31,
    kNumFPURegisters
  };

176
  explicit Simulator(Isolate* isolate);
177 178 179 180
  ~Simulator();

  // The currently executing Simulator instance. Potentially there can be one
  // for each native thread.
181
  static Simulator* current(v8::internal::Isolate* isolate);
182 183 184 185 186

  // Accessors for register state. Reading the pc value adheres to the MIPS
  // architecture specification and is off by a 8 from the currently executing
  // instruction.
  void set_register(int reg, int32_t value);
187
  void set_dw_register(int dreg, const int* dbl);
188
  int32_t get_register(int reg) const;
189
  double get_double_from_register_pair(int reg);
190
  // Same for FPURegisters.
191
  void set_fpu_register(int fpureg, int32_t value);
192
  void set_fpu_register_float(int fpureg, float value);
193 194
  void set_fpu_register_double(int fpureg, double value);
  int32_t get_fpu_register(int fpureg) const;
195 196
  int64_t get_fpu_register_long(int fpureg) const;
  float get_fpu_register_float(int fpureg) const;
197
  double get_fpu_register_double(int fpureg) const;
198 199 200
  void set_fcsr_bit(uint32_t cc, bool value);
  bool test_fcsr_bit(uint32_t cc);
  bool set_fcsr_round_error(double original, double rounded);
201 202 203 204 205 206 207 208 209 210 211 212

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

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

  // Executes MIPS instructions until the PC reaches end_sim_pc.
  void Execute();

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

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

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

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

228 229 230 231
  // Debugger input.
  void set_last_debugger_input(char* input);
  char* last_debugger_input() { return last_debugger_input_; }

232 233 234 235 236 237 238 239
  // ICache checking.
  static void FlushICache(v8::internal::HashMap* i_cache, void* start,
                          size_t size);

  // Returns true if pc register contains one of the 'special_values' defined
  // below (bad_ra, end_sim_pc).
  bool has_bad_pc() const;

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
 private:
  enum special_values {
    // Known bad pc value to ensure that the simulator does not execute
    // without being properly setup.
    bad_ra = -1,
    // A pc value used to signal the simulator to stop execution.  Generally
    // the ra is set to this value on transition from native C code to
    // simulated execution, so that the simulator can "return" to the native
    // C code.
    end_sim_pc = -2,
    // Unpredictable value.
    Unpredictable = 0xbadbeaf
  };

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

  // Read and write memory.
  inline uint32_t ReadBU(int32_t addr);
  inline int32_t ReadB(int32_t addr);
  inline void WriteB(int32_t addr, uint8_t value);
  inline void WriteB(int32_t addr, int8_t value);

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

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

  inline double ReadD(int32_t addr, Instruction* instr);
  inline void WriteD(int32_t addr, double value, Instruction* instr);

  // Operations depending on endianness.
  // Get Double Higher / Lower word.
  inline int32_t GetDoubleHIW(double* addr);
  inline int32_t GetDoubleLOW(double* addr);
  // Set Double Higher / Lower word.
  inline int32_t SetDoubleHIW(double* addr);
  inline int32_t SetDoubleLOW(double* addr);

  // Executing is handled based on the instruction type.
  void DecodeTypeRegister(Instruction* instr);
285 286 287 288 289 290 291

  // Helper function for DecodeTypeRegister.
  void ConfigureTypeRegister(Instruction* instr,
                             int32_t& alu_out,
                             int64_t& i64hilo,
                             uint64_t& u64hilo,
                             int32_t& next_pc,
292
                             int32_t& return_addr_reg,
293 294
                             bool& do_interrupt);

295 296 297 298 299 300
  void DecodeTypeImmediate(Instruction* instr);
  void DecodeTypeJump(Instruction* instr);

  // Used for breakpoints and traps.
  void SoftwareInterrupt(Instruction* instr);

301 302 303 304 305 306 307 308 309 310 311 312
  // Stop helper functions.
  bool IsWatchpoint(uint32_t code);
  void PrintWatchpoint(uint32_t code);
  void HandleStop(uint32_t code, Instruction* instr);
  bool IsStopInstruction(Instruction* instr);
  bool IsEnabledStop(uint32_t code);
  void EnableStop(uint32_t code);
  void DisableStop(uint32_t code);
  void IncreaseStopCounter(uint32_t code);
  void PrintStopInfo(uint32_t code);


313 314 315 316
  // Executes one instruction.
  void InstructionDecode(Instruction* instr);
  // Execute one instruction placed in a branch delay slot.
  void BranchDelayInstructionDecode(Instruction* instr) {
317 318 319 320 321 322
    if (instr->InstructionBits() == nopInstr) {
      // Short-cut generic nop instructions. They are always valid and they
      // never change the simulator state.
      return;
    }

323 324 325
    if (instr->IsForbiddenInBranchDelay()) {
      V8_Fatal(__FILE__, __LINE__,
               "Eror:Unexpected %i opcode in a branch delay slot.",
326
               instr->OpcodeValue());
327 328 329 330
    }
    InstructionDecode(instr);
  }

331 332 333 334 335 336
  // ICache.
  static void CheckICache(v8::internal::HashMap* i_cache, Instruction* instr);
  static void FlushOnePage(v8::internal::HashMap* i_cache, intptr_t start,
                           int size);
  static CachePage* GetCachePage(v8::internal::HashMap* i_cache, void* page);

337 338 339 340 341 342 343 344 345 346 347 348 349 350
  enum Exception {
    none,
    kIntegerOverflow,
    kIntegerUnderflow,
    kDivideByZero,
    kNumExceptions
  };
  int16_t exceptions[kNumExceptions];

  // Exceptions.
  void SignalExceptions();

  // Runtime call support.
  static void* RedirectExternalReference(void* external_function,
351
                                         ExternalReference::Type type);
352

353 354
  // Handle arguments and return value for runtime FP functions.
  void GetFpArgs(double* x, double* y, int32_t* z);
355 356
  void SetFpResult(const double& result);

357
  void CallInternal(byte* entry);
358 359 360 361 362 363

  // Architecture state.
  // Registers.
  int32_t registers_[kNumSimuRegisters];
  // Coprocessor Registers.
  int32_t FPUregisters_[kNumFPURegisters];
364 365
  // FPU control register.
  uint32_t FCSR_;
366 367

  // Simulator support.
368 369
  // Allocate 1MB for stack.
  static const size_t stack_size_ = 1 * 1024*1024;
370 371 372
  char* stack_;
  bool pc_modified_;
  int icount_;
373 374
  int break_count_;

375 376 377
  // Debugger input.
  char* last_debugger_input_;

378
  // Icache simulation.
379
  v8::internal::HashMap* i_cache_;
380

381 382
  v8::internal::Isolate* isolate_;

383 384 385
  // Registered breakpoints.
  Instruction* break_pc_;
  Instr break_instr_;
386 387 388 389 390

  // Stop is disabled if bit 31 is set.
  static const uint32_t kStopDisabledBit = 1 << 31;

  // A stop is enabled, meaning the simulator will stop when meeting the
391 392
  // instruction, if bit 31 of watched_stops_[code].count is unset.
  // The value watched_stops_[code].count & ~(1 << 31) indicates how many times
393 394 395 396 397
  // the breakpoint was hit or gone through.
  struct StopCountAndDesc {
    uint32_t count;
    char* desc;
  };
398
  StopCountAndDesc watched_stops_[kMaxStopCode + 1];
399 400
};

401 402 403 404

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

408
#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7, p8) \
409
    Simulator::current(Isolate::Current())->Call( \
410
        entry, 10, p0, p1, p2, p3, NULL, p4, p5, p6, p7, p8)
411

412 413
#define TRY_CATCH_FROM_ADDRESS(try_catch_address)                              \
  try_catch_address == NULL ?                                                  \
414
      NULL : *(reinterpret_cast<TryCatch**>(try_catch_address))
415 416 417 418 419 420 421 422 423


// The simulator has its own stack. Thus it has a different stack limit from
// the C-based native code.  Setting the c_limit to indicate a very small
// stack cause stack overflow errors, since the simulator ignores the input.
// This is unlikely to be an issue in practice, though it might cause testing
// trouble down the line.
class SimulatorStack : public v8::internal::AllStatic {
 public:
424 425 426
  static inline uintptr_t JsLimitFromCLimit(Isolate* isolate,
                                            uintptr_t c_limit) {
    return Simulator::current(isolate)->StackLimit();
427 428 429
  }

  static inline uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) {
430
    Simulator* sim = Simulator::current(Isolate::Current());
431 432 433 434
    return sim->PushAddress(try_catch_address);
  }

  static inline void UnregisterCTryCatch() {
435
    Simulator::current(Isolate::Current())->PopAddress();
436 437 438
  }
};

439
} }  // namespace v8::internal
440

441
#endif  // !defined(USE_SIMULATOR)
442
#endif  // V8_MIPS_SIMULATOR_MIPS_H_