blob: 7f60a7463929941e8939708db10083035282cd26 [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// Copyright 2011 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5
6// Declares a Simulator for MIPS instructions if we are not generating a native
7// MIPS binary. This Simulator allows us to run and debug MIPS code generation
8// on regular desktop machines.
9// V8 calls into generated code by "calling" the CALL_GENERATED_CODE macro,
10// which will start execution in the Simulator or forwards to the real entry
11// on a MIPS HW platform.
12
13#ifndef V8_MIPS_SIMULATOR_MIPS_H_
14#define V8_MIPS_SIMULATOR_MIPS_H_
15
16#include "src/allocation.h"
17#include "src/mips64/constants-mips64.h"
18
19#if !defined(USE_SIMULATOR)
20// Running without a simulator on a native mips platform.
21
22namespace v8 {
23namespace internal {
24
25// When running without a simulator we call the entry directly.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000026#define CALL_GENERATED_CODE(isolate, entry, p0, p1, p2, p3, p4) \
Ben Murdochb8a8cc12014-11-26 15:28:44 +000027 entry(p0, p1, p2, p3, p4)
28
29
30// Call the generated regexp code directly. The code at the entry address
31// should act as a function matching the type arm_regexp_matcher.
32// The fifth (or ninth) argument is a dummy that reserves the space used for
33// the return address added by the ExitFrame in native calls.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000034typedef int (*mips_regexp_matcher)(String* input,
35 int64_t start_offset,
36 const byte* input_start,
37 const byte* input_end,
38 int* output,
39 int64_t output_size,
40 Address stack_base,
41 int64_t direct_call,
42 void* return_address,
43 Isolate* isolate);
44
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000045#define CALL_GENERATED_REGEXP_CODE(isolate, entry, p0, p1, p2, p3, p4, p5, p6, \
46 p7, p8) \
47 (FUNCTION_CAST<mips_regexp_matcher>(entry)(p0, p1, p2, p3, p4, p5, p6, p7, \
48 NULL, p8))
Ben Murdochb8a8cc12014-11-26 15:28:44 +000049
Ben Murdochb8a8cc12014-11-26 15:28:44 +000050
51// The stack limit beyond which we will throw stack overflow errors in
52// generated code. Because generated code on mips uses the C stack, we
53// just use the C stack limit.
54class SimulatorStack : public v8::internal::AllStatic {
55 public:
56 static inline uintptr_t JsLimitFromCLimit(Isolate* isolate,
57 uintptr_t c_limit) {
58 return c_limit;
59 }
60
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000061 static inline uintptr_t RegisterCTryCatch(Isolate* isolate,
62 uintptr_t try_catch_address) {
63 USE(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000064 return try_catch_address;
65 }
66
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000067 static inline void UnregisterCTryCatch(Isolate* isolate) { USE(isolate); }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000068};
69
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000070} // namespace internal
71} // namespace v8
Ben Murdochb8a8cc12014-11-26 15:28:44 +000072
73// Calculated the stack limit beyond which we will throw stack overflow errors.
74// This macro must be called from a C++ method. It relies on being able to take
75// the address of "this" to get a value on the current execution stack and then
76// calculates the stack limit based on that value.
77// NOTE: The check for overflow is not safe as there is no guarantee that the
78// running thread has its stack in all memory up to address 0x00000000.
79#define GENERATED_CODE_STACK_LIMIT(limit) \
80 (reinterpret_cast<uintptr_t>(this) >= limit ? \
81 reinterpret_cast<uintptr_t>(this) - limit : 0)
82
83#else // !defined(USE_SIMULATOR)
84// Running with a simulator.
85
86#include "src/assembler.h"
87#include "src/hashmap.h"
88
89namespace v8 {
90namespace internal {
91
92// -----------------------------------------------------------------------------
93// Utility functions
94
95class CachePage {
96 public:
97 static const int LINE_VALID = 0;
98 static const int LINE_INVALID = 1;
99
100 static const int kPageShift = 12;
101 static const int kPageSize = 1 << kPageShift;
102 static const int kPageMask = kPageSize - 1;
103 static const int kLineShift = 2; // The cache line is only 4 bytes right now.
104 static const int kLineLength = 1 << kLineShift;
105 static const int kLineMask = kLineLength - 1;
106
107 CachePage() {
108 memset(&validity_map_, LINE_INVALID, sizeof(validity_map_));
109 }
110
111 char* ValidityByte(int offset) {
112 return &validity_map_[offset >> kLineShift];
113 }
114
115 char* CachedData(int offset) {
116 return &data_[offset];
117 }
118
119 private:
120 char data_[kPageSize]; // The cached data.
121 static const int kValidityMapSize = kPageSize >> kLineShift;
122 char validity_map_[kValidityMapSize]; // One byte per line.
123};
124
125class Simulator {
126 public:
127 friend class MipsDebugger;
128
129 // Registers are declared in order. See SMRL chapter 2.
130 enum Register {
131 no_reg = -1,
132 zero_reg = 0,
133 at,
134 v0, v1,
135 a0, a1, a2, a3, a4, a5, a6, a7,
136 t0, t1, t2, t3,
137 s0, s1, s2, s3, s4, s5, s6, s7,
138 t8, t9,
139 k0, k1,
140 gp,
141 sp,
142 s8,
143 ra,
144 // LO, HI, and pc.
145 LO,
146 HI,
147 pc, // pc must be the last register.
148 kNumSimuRegisters,
149 // aliases
150 fp = s8
151 };
152
153 // Coprocessor registers.
154 // Generated code will always use doubles. So we will only use even registers.
155 enum FPURegister {
156 f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11,
157 f12, f13, f14, f15, // f12 and f14 are arguments FPURegisters.
158 f16, f17, f18, f19, f20, f21, f22, f23, f24, f25,
159 f26, f27, f28, f29, f30, f31,
160 kNumFPURegisters
161 };
162
163 explicit Simulator(Isolate* isolate);
164 ~Simulator();
165
166 // The currently executing Simulator instance. Potentially there can be one
167 // for each native thread.
168 static Simulator* current(v8::internal::Isolate* isolate);
169
170 // Accessors for register state. Reading the pc value adheres to the MIPS
171 // architecture specification and is off by a 8 from the currently executing
172 // instruction.
173 void set_register(int reg, int64_t value);
174 void set_register_word(int reg, int32_t value);
175 void set_dw_register(int dreg, const int* dbl);
176 int64_t get_register(int reg) const;
177 double get_double_from_register_pair(int reg);
178 // Same for FPURegisters.
179 void set_fpu_register(int fpureg, int64_t value);
180 void set_fpu_register_word(int fpureg, int32_t value);
181 void set_fpu_register_hi_word(int fpureg, int32_t value);
182 void set_fpu_register_float(int fpureg, float value);
183 void set_fpu_register_double(int fpureg, double value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000184 void set_fpu_register_invalid_result64(float original, float rounded);
185 void set_fpu_register_invalid_result(float original, float rounded);
186 void set_fpu_register_word_invalid_result(float original, float rounded);
187 void set_fpu_register_invalid_result64(double original, double rounded);
188 void set_fpu_register_invalid_result(double original, double rounded);
189 void set_fpu_register_word_invalid_result(double original, double rounded);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000190 int64_t get_fpu_register(int fpureg) const;
191 int32_t get_fpu_register_word(int fpureg) const;
192 int32_t get_fpu_register_signed_word(int fpureg) const;
193 int32_t get_fpu_register_hi_word(int fpureg) const;
194 float get_fpu_register_float(int fpureg) const;
195 double get_fpu_register_double(int fpureg) const;
196 void set_fcsr_bit(uint32_t cc, bool value);
197 bool test_fcsr_bit(uint32_t cc);
198 bool set_fcsr_round_error(double original, double rounded);
199 bool set_fcsr_round64_error(double original, double rounded);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000200 bool set_fcsr_round_error(float original, float rounded);
201 bool set_fcsr_round64_error(float original, float rounded);
202 void round_according_to_fcsr(double toRound, double& rounded,
203 int32_t& rounded_int, double fs);
204 void round64_according_to_fcsr(double toRound, double& rounded,
205 int64_t& rounded_int, double fs);
206 void round_according_to_fcsr(float toRound, float& rounded,
207 int32_t& rounded_int, float fs);
208 void round64_according_to_fcsr(float toRound, float& rounded,
209 int64_t& rounded_int, float fs);
210 void set_fcsr_rounding_mode(FPURoundingMode mode);
211 unsigned int get_fcsr_rounding_mode();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000212 // Special case of set_register and get_register to access the raw PC value.
213 void set_pc(int64_t value);
214 int64_t get_pc() const;
215
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000216 Address get_sp() const {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000217 return reinterpret_cast<Address>(static_cast<intptr_t>(get_register(sp)));
218 }
219
220 // Accessor to the internal simulator stack area.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000221 uintptr_t StackLimit(uintptr_t c_limit) const;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000222
223 // Executes MIPS instructions until the PC reaches end_sim_pc.
224 void Execute();
225
226 // Call on program start.
227 static void Initialize(Isolate* isolate);
228
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000229 static void TearDown(HashMap* i_cache, Redirection* first);
230
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000231 // V8 generally calls into generated JS code with 5 parameters and into
232 // generated RegExp code with 7 parameters. This is a convenience function,
233 // which sets up the simulator state and grabs the result on return.
234 int64_t Call(byte* entry, int argument_count, ...);
235 // Alternative: call a 2-argument double function.
236 double CallFP(byte* entry, double d0, double d1);
237
238 // Push an address onto the JS stack.
239 uintptr_t PushAddress(uintptr_t address);
240
241 // Pop an address from the JS stack.
242 uintptr_t PopAddress();
243
244 // Debugger input.
245 void set_last_debugger_input(char* input);
246 char* last_debugger_input() { return last_debugger_input_; }
247
248 // ICache checking.
249 static void FlushICache(v8::internal::HashMap* i_cache, void* start,
250 size_t size);
251
252 // Returns true if pc register contains one of the 'special_values' defined
253 // below (bad_ra, end_sim_pc).
254 bool has_bad_pc() const;
255
256 private:
257 enum special_values {
258 // Known bad pc value to ensure that the simulator does not execute
259 // without being properly setup.
260 bad_ra = -1,
261 // A pc value used to signal the simulator to stop execution. Generally
262 // the ra is set to this value on transition from native C code to
263 // simulated execution, so that the simulator can "return" to the native
264 // C code.
265 end_sim_pc = -2,
266 // Unpredictable value.
267 Unpredictable = 0xbadbeaf
268 };
269
270 // Unsupported instructions use Format to print an error and stop execution.
271 void Format(Instruction* instr, const char* format);
272
273 // Read and write memory.
274 inline uint32_t ReadBU(int64_t addr);
275 inline int32_t ReadB(int64_t addr);
276 inline void WriteB(int64_t addr, uint8_t value);
277 inline void WriteB(int64_t addr, int8_t value);
278
279 inline uint16_t ReadHU(int64_t addr, Instruction* instr);
280 inline int16_t ReadH(int64_t addr, Instruction* instr);
281 // Note: Overloaded on the sign of the value.
282 inline void WriteH(int64_t addr, uint16_t value, Instruction* instr);
283 inline void WriteH(int64_t addr, int16_t value, Instruction* instr);
284
285 inline uint32_t ReadWU(int64_t addr, Instruction* instr);
286 inline int32_t ReadW(int64_t addr, Instruction* instr);
287 inline void WriteW(int64_t addr, int32_t value, Instruction* instr);
288 inline int64_t Read2W(int64_t addr, Instruction* instr);
289 inline void Write2W(int64_t addr, int64_t value, Instruction* instr);
290
291 inline double ReadD(int64_t addr, Instruction* instr);
292 inline void WriteD(int64_t addr, double value, Instruction* instr);
293
294 // Helper for debugging memory access.
295 inline void DieOrDebug();
296
297 // Helpers for data value tracing.
298 enum TraceType {
299 BYTE,
300 HALF,
301 WORD,
302 DWORD
303 // DFLOAT - Floats may have printing issues due to paired lwc1's
304 };
305
306 void TraceRegWr(int64_t value);
307 void TraceMemWr(int64_t addr, int64_t value, TraceType t);
308 void TraceMemRd(int64_t addr, int64_t value);
309
310 // Operations depending on endianness.
311 // Get Double Higher / Lower word.
312 inline int32_t GetDoubleHIW(double* addr);
313 inline int32_t GetDoubleLOW(double* addr);
314 // Set Double Higher / Lower word.
315 inline int32_t SetDoubleHIW(double* addr);
316 inline int32_t SetDoubleLOW(double* addr);
317
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000318 // functions called from DecodeTypeRegister.
319 void DecodeTypeRegisterCOP1();
320
321 void DecodeTypeRegisterCOP1X();
322
323 void DecodeTypeRegisterSPECIAL();
324
325
326 void DecodeTypeRegisterSPECIAL2();
327
328 void DecodeTypeRegisterSPECIAL3();
329
330 void DecodeTypeRegisterSRsType();
331
332 void DecodeTypeRegisterDRsType();
333
334 void DecodeTypeRegisterWRsType();
335
336 void DecodeTypeRegisterLRsType();
337
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000338 // Executing is handled based on the instruction type.
339 void DecodeTypeRegister(Instruction* instr);
340
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000341 Instruction* currentInstr_;
342 inline Instruction* get_instr() const { return currentInstr_; }
343 inline void set_instr(Instruction* instr) { currentInstr_ = instr; }
344
345 inline int32_t rs_reg() const { return currentInstr_->RsValue(); }
346 inline int64_t rs() const { return get_register(rs_reg()); }
347 inline uint64_t rs_u() const {
348 return static_cast<uint64_t>(get_register(rs_reg()));
349 }
350 inline int32_t rt_reg() const { return currentInstr_->RtValue(); }
351 inline int64_t rt() const { return get_register(rt_reg()); }
352 inline uint64_t rt_u() const {
353 return static_cast<uint64_t>(get_register(rt_reg()));
354 }
355 inline int32_t rd_reg() const { return currentInstr_->RdValue(); }
356 inline int32_t fr_reg() const { return currentInstr_->FrValue(); }
357 inline int32_t fs_reg() const { return currentInstr_->FsValue(); }
358 inline int32_t ft_reg() const { return currentInstr_->FtValue(); }
359 inline int32_t fd_reg() const { return currentInstr_->FdValue(); }
360 inline int32_t sa() const { return currentInstr_->SaValue(); }
361 inline int32_t lsa_sa() const { return currentInstr_->LsaSaValue(); }
362
363 inline void SetResult(const int32_t rd_reg, const int64_t alu_out) {
364 set_register(rd_reg, alu_out);
365 TraceRegWr(alu_out);
366 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000367
368 void DecodeTypeImmediate(Instruction* instr);
369 void DecodeTypeJump(Instruction* instr);
370
371 // Used for breakpoints and traps.
372 void SoftwareInterrupt(Instruction* instr);
373
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000374 // Compact branch guard.
375 void CheckForbiddenSlot(int64_t current_pc) {
376 Instruction* instr_after_compact_branch =
377 reinterpret_cast<Instruction*>(current_pc + Instruction::kInstrSize);
378 if (instr_after_compact_branch->IsForbiddenAfterBranch()) {
379 V8_Fatal(__FILE__, __LINE__,
380 "Error: Unexpected instruction 0x%08x immediately after a "
381 "compact branch instruction.",
382 *reinterpret_cast<uint32_t*>(instr_after_compact_branch));
383 }
384 }
385
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000386 // Stop helper functions.
387 bool IsWatchpoint(uint64_t code);
388 void PrintWatchpoint(uint64_t code);
389 void HandleStop(uint64_t code, Instruction* instr);
390 bool IsStopInstruction(Instruction* instr);
391 bool IsEnabledStop(uint64_t code);
392 void EnableStop(uint64_t code);
393 void DisableStop(uint64_t code);
394 void IncreaseStopCounter(uint64_t code);
395 void PrintStopInfo(uint64_t code);
396
397
398 // Executes one instruction.
399 void InstructionDecode(Instruction* instr);
400 // Execute one instruction placed in a branch delay slot.
401 void BranchDelayInstructionDecode(Instruction* instr) {
402 if (instr->InstructionBits() == nopInstr) {
403 // Short-cut generic nop instructions. They are always valid and they
404 // never change the simulator state.
405 return;
406 }
407
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000408 if (instr->IsForbiddenAfterBranch()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000409 V8_Fatal(__FILE__, __LINE__,
410 "Eror:Unexpected %i opcode in a branch delay slot.",
411 instr->OpcodeValue());
412 }
413 InstructionDecode(instr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000414 SNPrintF(trace_buf_, " ");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000415 }
416
417 // ICache.
418 static void CheckICache(v8::internal::HashMap* i_cache, Instruction* instr);
419 static void FlushOnePage(v8::internal::HashMap* i_cache, intptr_t start,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000420 size_t size);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000421 static CachePage* GetCachePage(v8::internal::HashMap* i_cache, void* page);
422
423 enum Exception {
424 none,
425 kIntegerOverflow,
426 kIntegerUnderflow,
427 kDivideByZero,
428 kNumExceptions
429 };
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000430
431 // Exceptions.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000432 void SignalException(Exception e);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000433
434 // Runtime call support.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000435 static void* RedirectExternalReference(Isolate* isolate,
436 void* external_function,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000437 ExternalReference::Type type);
438
439 // Handle arguments and return value for runtime FP functions.
440 void GetFpArgs(double* x, double* y, int32_t* z);
441 void SetFpResult(const double& result);
442
443 void CallInternal(byte* entry);
444
445 // Architecture state.
446 // Registers.
447 int64_t registers_[kNumSimuRegisters];
448 // Coprocessor Registers.
449 int64_t FPUregisters_[kNumFPURegisters];
450 // FPU control register.
451 uint32_t FCSR_;
452
453 // Simulator support.
454 // Allocate 1MB for stack.
455 size_t stack_size_;
456 char* stack_;
457 bool pc_modified_;
458 int64_t icount_;
459 int break_count_;
460 EmbeddedVector<char, 128> trace_buf_;
461
462 // Debugger input.
463 char* last_debugger_input_;
464
465 // Icache simulation.
466 v8::internal::HashMap* i_cache_;
467
468 v8::internal::Isolate* isolate_;
469
470 // Registered breakpoints.
471 Instruction* break_pc_;
472 Instr break_instr_;
473
474 // Stop is disabled if bit 31 is set.
475 static const uint32_t kStopDisabledBit = 1 << 31;
476
477 // A stop is enabled, meaning the simulator will stop when meeting the
478 // instruction, if bit 31 of watched_stops_[code].count is unset.
479 // The value watched_stops_[code].count & ~(1 << 31) indicates how many times
480 // the breakpoint was hit or gone through.
481 struct StopCountAndDesc {
482 uint32_t count;
483 char* desc;
484 };
485 StopCountAndDesc watched_stops_[kMaxStopCode + 1];
486};
487
488
489// When running with the simulator transition into simulated execution at this
490// point.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000491#define CALL_GENERATED_CODE(isolate, entry, p0, p1, p2, p3, p4) \
492 reinterpret_cast<Object*>(Simulator::current(isolate)->Call( \
493 FUNCTION_ADDR(entry), 5, reinterpret_cast<int64_t*>(p0), \
494 reinterpret_cast<int64_t*>(p1), reinterpret_cast<int64_t*>(p2), \
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400495 reinterpret_cast<int64_t*>(p3), reinterpret_cast<int64_t*>(p4)))
496
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000497
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000498#define CALL_GENERATED_REGEXP_CODE(isolate, entry, p0, p1, p2, p3, p4, p5, p6, \
499 p7, p8) \
500 static_cast<int>(Simulator::current(isolate)->Call( \
501 entry, 10, p0, p1, p2, p3, p4, reinterpret_cast<int64_t*>(p5), p6, p7, \
502 NULL, p8))
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000503
504
505// The simulator has its own stack. Thus it has a different stack limit from
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000506// the C-based native code. The JS-based limit normally points near the end of
507// the simulator stack. When the C-based limit is exhausted we reflect that by
508// lowering the JS-based limit as well, to make stack checks trigger.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000509class SimulatorStack : public v8::internal::AllStatic {
510 public:
511 static inline uintptr_t JsLimitFromCLimit(Isolate* isolate,
512 uintptr_t c_limit) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000513 return Simulator::current(isolate)->StackLimit(c_limit);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000514 }
515
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000516 static inline uintptr_t RegisterCTryCatch(Isolate* isolate,
517 uintptr_t try_catch_address) {
518 Simulator* sim = Simulator::current(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000519 return sim->PushAddress(try_catch_address);
520 }
521
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000522 static inline void UnregisterCTryCatch(Isolate* isolate) {
523 Simulator::current(isolate)->PopAddress();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000524 }
525};
526
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000527} // namespace internal
528} // namespace v8
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000529
530#endif // !defined(USE_SIMULATOR)
531#endif // V8_MIPS_SIMULATOR_MIPS_H_