blob: 85f64779f12551fd6c77c3304f82aeb8d3128c08 [file] [log] [blame]
Ben Murdoch257744e2011-11-30 15:57:28 +00001// Copyright 2011 the V8 project authors. All rights reserved.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
Andrei Popescu31002712010-02-23 13:46:05 +00004
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
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016#include "src/allocation.h"
17#include "src/mips/constants-mips.h"
Andrei Popescu31002712010-02-23 13:46:05 +000018
Steve Block44f0eee2011-05-26 01:26:41 +010019#if !defined(USE_SIMULATOR)
20// Running without a simulator on a native mips platform.
21
22namespace v8 {
23namespace internal {
Andrei Popescu31002712010-02-23 13:46:05 +000024
25// When running without a simulator we call the entry directly.
26#define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \
Steve Block44f0eee2011-05-26 01:26:41 +010027 entry(p0, p1, p2, p3, p4)
28
29typedef int (*mips_regexp_matcher)(String*, int, const byte*, const byte*,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000030 void*, int*, int, Address, int, Isolate*);
Ben Murdoch257744e2011-11-30 15:57:28 +000031
Steve Block44f0eee2011-05-26 01:26:41 +010032
33// Call the generated regexp code directly. The code at the entry address
34// should act as a function matching the type arm_regexp_matcher.
35// The fifth argument is a dummy that reserves the space used for
36// the return address added by the ExitFrame in native calls.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000037#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7, p8) \
Ben Murdoch257744e2011-11-30 15:57:28 +000038 (FUNCTION_CAST<mips_regexp_matcher>(entry)( \
Ben Murdochb8a8cc12014-11-26 15:28:44 +000039 p0, p1, p2, p3, NULL, p4, p5, p6, p7, p8))
Andrei Popescu31002712010-02-23 13:46:05 +000040
41// The stack limit beyond which we will throw stack overflow errors in
42// generated code. Because generated code on mips uses the C stack, we
43// just use the C stack limit.
44class SimulatorStack : public v8::internal::AllStatic {
45 public:
Ben Murdoch257744e2011-11-30 15:57:28 +000046 static inline uintptr_t JsLimitFromCLimit(Isolate* isolate,
47 uintptr_t c_limit) {
Andrei Popescu31002712010-02-23 13:46:05 +000048 return c_limit;
49 }
50
51 static inline uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) {
52 return try_catch_address;
53 }
54
55 static inline void UnregisterCTryCatch() { }
56};
57
Steve Block44f0eee2011-05-26 01:26:41 +010058} } // namespace v8::internal
59
Andrei Popescu31002712010-02-23 13:46:05 +000060// Calculated the stack limit beyond which we will throw stack overflow errors.
61// This macro must be called from a C++ method. It relies on being able to take
62// the address of "this" to get a value on the current execution stack and then
63// calculates the stack limit based on that value.
64// NOTE: The check for overflow is not safe as there is no guarantee that the
65// running thread has its stack in all memory up to address 0x00000000.
66#define GENERATED_CODE_STACK_LIMIT(limit) \
67 (reinterpret_cast<uintptr_t>(this) >= limit ? \
68 reinterpret_cast<uintptr_t>(this) - limit : 0)
69
Steve Block44f0eee2011-05-26 01:26:41 +010070#else // !defined(USE_SIMULATOR)
71// Running with a simulator.
Andrei Popescu31002712010-02-23 13:46:05 +000072
Ben Murdochb8a8cc12014-11-26 15:28:44 +000073#include "src/assembler.h"
74#include "src/hashmap.h"
Andrei Popescu31002712010-02-23 13:46:05 +000075
Steve Block44f0eee2011-05-26 01:26:41 +010076namespace v8 {
77namespace internal {
Andrei Popescu31002712010-02-23 13:46:05 +000078
Steve Block44f0eee2011-05-26 01:26:41 +010079// -----------------------------------------------------------------------------
80// Utility functions
Andrei Popescu31002712010-02-23 13:46:05 +000081
Steve Block44f0eee2011-05-26 01:26:41 +010082class CachePage {
83 public:
84 static const int LINE_VALID = 0;
85 static const int LINE_INVALID = 1;
Andrei Popescu31002712010-02-23 13:46:05 +000086
Steve Block44f0eee2011-05-26 01:26:41 +010087 static const int kPageShift = 12;
88 static const int kPageSize = 1 << kPageShift;
89 static const int kPageMask = kPageSize - 1;
90 static const int kLineShift = 2; // The cache line is only 4 bytes right now.
91 static const int kLineLength = 1 << kLineShift;
92 static const int kLineMask = kLineLength - 1;
Andrei Popescu31002712010-02-23 13:46:05 +000093
Steve Block44f0eee2011-05-26 01:26:41 +010094 CachePage() {
95 memset(&validity_map_, LINE_INVALID, sizeof(validity_map_));
96 }
Andrei Popescu31002712010-02-23 13:46:05 +000097
Steve Block44f0eee2011-05-26 01:26:41 +010098 char* ValidityByte(int offset) {
99 return &validity_map_[offset >> kLineShift];
100 }
Andrei Popescu31002712010-02-23 13:46:05 +0000101
Steve Block44f0eee2011-05-26 01:26:41 +0100102 char* CachedData(int offset) {
103 return &data_[offset];
104 }
105
106 private:
107 char data_[kPageSize]; // The cached data.
108 static const int kValidityMapSize = kPageSize >> kLineShift;
109 char validity_map_[kValidityMapSize]; // One byte per line.
110};
Andrei Popescu31002712010-02-23 13:46:05 +0000111
112class Simulator {
113 public:
Steve Block44f0eee2011-05-26 01:26:41 +0100114 friend class MipsDebugger;
Andrei Popescu31002712010-02-23 13:46:05 +0000115
116 // Registers are declared in order. See SMRL chapter 2.
117 enum Register {
118 no_reg = -1,
119 zero_reg = 0,
120 at,
121 v0, v1,
122 a0, a1, a2, a3,
123 t0, t1, t2, t3, t4, t5, t6, t7,
124 s0, s1, s2, s3, s4, s5, s6, s7,
125 t8, t9,
126 k0, k1,
127 gp,
128 sp,
129 s8,
130 ra,
Ben Murdoch257744e2011-11-30 15:57:28 +0000131 // LO, HI, and pc.
Andrei Popescu31002712010-02-23 13:46:05 +0000132 LO,
133 HI,
134 pc, // pc must be the last register.
135 kNumSimuRegisters,
136 // aliases
137 fp = s8
138 };
139
140 // Coprocessor registers.
141 // Generated code will always use doubles. So we will only use even registers.
142 enum FPURegister {
143 f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11,
Ben Murdoch257744e2011-11-30 15:57:28 +0000144 f12, f13, f14, f15, // f12 and f14 are arguments FPURegisters.
Andrei Popescu31002712010-02-23 13:46:05 +0000145 f16, f17, f18, f19, f20, f21, f22, f23, f24, f25,
146 f26, f27, f28, f29, f30, f31,
147 kNumFPURegisters
148 };
149
Ben Murdoch257744e2011-11-30 15:57:28 +0000150 explicit Simulator(Isolate* isolate);
Andrei Popescu31002712010-02-23 13:46:05 +0000151 ~Simulator();
152
153 // The currently executing Simulator instance. Potentially there can be one
154 // for each native thread.
Steve Block44f0eee2011-05-26 01:26:41 +0100155 static Simulator* current(v8::internal::Isolate* isolate);
Andrei Popescu31002712010-02-23 13:46:05 +0000156
157 // Accessors for register state. Reading the pc value adheres to the MIPS
158 // architecture specification and is off by a 8 from the currently executing
159 // instruction.
160 void set_register(int reg, int32_t value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000161 void set_dw_register(int dreg, const int* dbl);
Andrei Popescu31002712010-02-23 13:46:05 +0000162 int32_t get_register(int reg) const;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000163 double get_double_from_register_pair(int reg);
Ben Murdoch257744e2011-11-30 15:57:28 +0000164 // Same for FPURegisters.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000165 void set_fpu_register(int fpureg, int64_t value);
166 void set_fpu_register_word(int fpureg, int32_t value);
167 void set_fpu_register_hi_word(int fpureg, int32_t value);
Steve Block44f0eee2011-05-26 01:26:41 +0100168 void set_fpu_register_float(int fpureg, float value);
Andrei Popescu31002712010-02-23 13:46:05 +0000169 void set_fpu_register_double(int fpureg, double value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000170 int64_t get_fpu_register(int fpureg) const;
171 int32_t get_fpu_register_word(int fpureg) const;
172 int32_t get_fpu_register_signed_word(int fpureg) const;
173 int32_t get_fpu_register_hi_word(int fpureg) const;
Steve Block44f0eee2011-05-26 01:26:41 +0100174 float get_fpu_register_float(int fpureg) const;
Andrei Popescu31002712010-02-23 13:46:05 +0000175 double get_fpu_register_double(int fpureg) const;
Steve Block44f0eee2011-05-26 01:26:41 +0100176 void set_fcsr_bit(uint32_t cc, bool value);
177 bool test_fcsr_bit(uint32_t cc);
178 bool set_fcsr_round_error(double original, double rounded);
Andrei Popescu31002712010-02-23 13:46:05 +0000179
180 // Special case of set_register and get_register to access the raw PC value.
181 void set_pc(int32_t value);
182 int32_t get_pc() const;
183
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000184 Address get_sp() {
185 return reinterpret_cast<Address>(static_cast<intptr_t>(get_register(sp)));
186 }
187
Andrei Popescu31002712010-02-23 13:46:05 +0000188 // Accessor to the internal simulator stack area.
189 uintptr_t StackLimit() const;
190
191 // Executes MIPS instructions until the PC reaches end_sim_pc.
192 void Execute();
193
194 // Call on program start.
Ben Murdoch257744e2011-11-30 15:57:28 +0000195 static void Initialize(Isolate* isolate);
Andrei Popescu31002712010-02-23 13:46:05 +0000196
197 // V8 generally calls into generated JS code with 5 parameters and into
198 // generated RegExp code with 7 parameters. This is a convenience function,
199 // which sets up the simulator state and grabs the result on return.
Steve Block44f0eee2011-05-26 01:26:41 +0100200 int32_t Call(byte* entry, int argument_count, ...);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000201 // Alternative: call a 2-argument double function.
202 double CallFP(byte* entry, double d0, double d1);
Andrei Popescu31002712010-02-23 13:46:05 +0000203
204 // Push an address onto the JS stack.
205 uintptr_t PushAddress(uintptr_t address);
206
207 // Pop an address from the JS stack.
208 uintptr_t PopAddress();
209
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100210 // Debugger input.
211 void set_last_debugger_input(char* input);
212 char* last_debugger_input() { return last_debugger_input_; }
213
Steve Block44f0eee2011-05-26 01:26:41 +0100214 // ICache checking.
215 static void FlushICache(v8::internal::HashMap* i_cache, void* start,
216 size_t size);
217
218 // Returns true if pc register contains one of the 'special_values' defined
219 // below (bad_ra, end_sim_pc).
220 bool has_bad_pc() const;
221
Andrei Popescu31002712010-02-23 13:46:05 +0000222 private:
223 enum special_values {
224 // Known bad pc value to ensure that the simulator does not execute
225 // without being properly setup.
226 bad_ra = -1,
227 // A pc value used to signal the simulator to stop execution. Generally
228 // the ra is set to this value on transition from native C code to
229 // simulated execution, so that the simulator can "return" to the native
230 // C code.
231 end_sim_pc = -2,
232 // Unpredictable value.
233 Unpredictable = 0xbadbeaf
234 };
235
236 // Unsupported instructions use Format to print an error and stop execution.
237 void Format(Instruction* instr, const char* format);
238
239 // Read and write memory.
240 inline uint32_t ReadBU(int32_t addr);
241 inline int32_t ReadB(int32_t addr);
242 inline void WriteB(int32_t addr, uint8_t value);
243 inline void WriteB(int32_t addr, int8_t value);
244
245 inline uint16_t ReadHU(int32_t addr, Instruction* instr);
246 inline int16_t ReadH(int32_t addr, Instruction* instr);
247 // Note: Overloaded on the sign of the value.
248 inline void WriteH(int32_t addr, uint16_t value, Instruction* instr);
249 inline void WriteH(int32_t addr, int16_t value, Instruction* instr);
250
251 inline int ReadW(int32_t addr, Instruction* instr);
252 inline void WriteW(int32_t addr, int value, Instruction* instr);
253
254 inline double ReadD(int32_t addr, Instruction* instr);
255 inline void WriteD(int32_t addr, double value, Instruction* instr);
256
257 // Operations depending on endianness.
258 // Get Double Higher / Lower word.
259 inline int32_t GetDoubleHIW(double* addr);
260 inline int32_t GetDoubleLOW(double* addr);
261 // Set Double Higher / Lower word.
262 inline int32_t SetDoubleHIW(double* addr);
263 inline int32_t SetDoubleLOW(double* addr);
264
Andrei Popescu31002712010-02-23 13:46:05 +0000265 // Executing is handled based on the instruction type.
266 void DecodeTypeRegister(Instruction* instr);
Steve Block44f0eee2011-05-26 01:26:41 +0100267
268 // Helper function for DecodeTypeRegister.
269 void ConfigureTypeRegister(Instruction* instr,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000270 int32_t* alu_out,
271 int64_t* i64hilo,
272 uint64_t* u64hilo,
273 int32_t* next_pc,
274 int32_t* return_addr_reg,
275 bool* do_interrupt);
Steve Block44f0eee2011-05-26 01:26:41 +0100276
Andrei Popescu31002712010-02-23 13:46:05 +0000277 void DecodeTypeImmediate(Instruction* instr);
278 void DecodeTypeJump(Instruction* instr);
279
280 // Used for breakpoints and traps.
281 void SoftwareInterrupt(Instruction* instr);
282
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000283 // Stop helper functions.
284 bool IsWatchpoint(uint32_t code);
285 void PrintWatchpoint(uint32_t code);
286 void HandleStop(uint32_t code, Instruction* instr);
287 bool IsStopInstruction(Instruction* instr);
288 bool IsEnabledStop(uint32_t code);
289 void EnableStop(uint32_t code);
290 void DisableStop(uint32_t code);
291 void IncreaseStopCounter(uint32_t code);
292 void PrintStopInfo(uint32_t code);
293
294
Andrei Popescu31002712010-02-23 13:46:05 +0000295 // Executes one instruction.
296 void InstructionDecode(Instruction* instr);
297 // Execute one instruction placed in a branch delay slot.
298 void BranchDelayInstructionDecode(Instruction* instr) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100299 if (instr->InstructionBits() == nopInstr) {
300 // Short-cut generic nop instructions. They are always valid and they
301 // never change the simulator state.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100302 return;
303 }
304
Andrei Popescu31002712010-02-23 13:46:05 +0000305 if (instr->IsForbiddenInBranchDelay()) {
306 V8_Fatal(__FILE__, __LINE__,
307 "Eror:Unexpected %i opcode in a branch delay slot.",
Steve Block44f0eee2011-05-26 01:26:41 +0100308 instr->OpcodeValue());
Andrei Popescu31002712010-02-23 13:46:05 +0000309 }
310 InstructionDecode(instr);
311 }
312
Steve Block44f0eee2011-05-26 01:26:41 +0100313 // ICache.
314 static void CheckICache(v8::internal::HashMap* i_cache, Instruction* instr);
315 static void FlushOnePage(v8::internal::HashMap* i_cache, intptr_t start,
316 int size);
317 static CachePage* GetCachePage(v8::internal::HashMap* i_cache, void* page);
318
Andrei Popescu31002712010-02-23 13:46:05 +0000319 enum Exception {
320 none,
321 kIntegerOverflow,
322 kIntegerUnderflow,
323 kDivideByZero,
324 kNumExceptions
325 };
326 int16_t exceptions[kNumExceptions];
327
328 // Exceptions.
329 void SignalExceptions();
330
331 // Runtime call support.
332 static void* RedirectExternalReference(void* external_function,
Steve Block44f0eee2011-05-26 01:26:41 +0100333 ExternalReference::Type type);
Andrei Popescu31002712010-02-23 13:46:05 +0000334
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000335 // Handle arguments and return value for runtime FP functions.
336 void GetFpArgs(double* x, double* y, int32_t* z);
Ben Murdoch257744e2011-11-30 15:57:28 +0000337 void SetFpResult(const double& result);
338
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000339 void CallInternal(byte* entry);
Andrei Popescu31002712010-02-23 13:46:05 +0000340
341 // Architecture state.
342 // Registers.
343 int32_t registers_[kNumSimuRegisters];
344 // Coprocessor Registers.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000345 // Note: FP32 mode uses only the lower 32-bit part of each element,
346 // the upper 32-bit is unpredictable.
347 int64_t FPUregisters_[kNumFPURegisters];
Steve Block44f0eee2011-05-26 01:26:41 +0100348 // FPU control register.
349 uint32_t FCSR_;
Andrei Popescu31002712010-02-23 13:46:05 +0000350
351 // Simulator support.
Ben Murdoch257744e2011-11-30 15:57:28 +0000352 // Allocate 1MB for stack.
353 static const size_t stack_size_ = 1 * 1024*1024;
Andrei Popescu31002712010-02-23 13:46:05 +0000354 char* stack_;
355 bool pc_modified_;
356 int icount_;
Steve Block44f0eee2011-05-26 01:26:41 +0100357 int break_count_;
358
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100359 // Debugger input.
360 char* last_debugger_input_;
361
Ben Murdoch257744e2011-11-30 15:57:28 +0000362 // Icache simulation.
Steve Block44f0eee2011-05-26 01:26:41 +0100363 v8::internal::HashMap* i_cache_;
Andrei Popescu31002712010-02-23 13:46:05 +0000364
Ben Murdoch257744e2011-11-30 15:57:28 +0000365 v8::internal::Isolate* isolate_;
366
Andrei Popescu31002712010-02-23 13:46:05 +0000367 // Registered breakpoints.
368 Instruction* break_pc_;
369 Instr break_instr_;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000370
371 // Stop is disabled if bit 31 is set.
372 static const uint32_t kStopDisabledBit = 1 << 31;
373
374 // A stop is enabled, meaning the simulator will stop when meeting the
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000375 // instruction, if bit 31 of watched_stops_[code].count is unset.
376 // The value watched_stops_[code].count & ~(1 << 31) indicates how many times
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000377 // the breakpoint was hit or gone through.
378 struct StopCountAndDesc {
379 uint32_t count;
380 char* desc;
381 };
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000382 StopCountAndDesc watched_stops_[kMaxStopCode + 1];
Andrei Popescu31002712010-02-23 13:46:05 +0000383};
384
Steve Block44f0eee2011-05-26 01:26:41 +0100385
386// When running with the simulator transition into simulated execution at this
387// point.
388#define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \
Ben Murdoch257744e2011-11-30 15:57:28 +0000389 reinterpret_cast<Object*>(Simulator::current(Isolate::Current())->Call( \
Steve Block44f0eee2011-05-26 01:26:41 +0100390 FUNCTION_ADDR(entry), 5, p0, p1, p2, p3, p4))
391
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000392#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7, p8) \
Ben Murdoch257744e2011-11-30 15:57:28 +0000393 Simulator::current(Isolate::Current())->Call( \
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000394 entry, 10, p0, p1, p2, p3, NULL, p4, p5, p6, p7, p8)
Andrei Popescu31002712010-02-23 13:46:05 +0000395
396
397// The simulator has its own stack. Thus it has a different stack limit from
398// the C-based native code. Setting the c_limit to indicate a very small
399// stack cause stack overflow errors, since the simulator ignores the input.
400// This is unlikely to be an issue in practice, though it might cause testing
401// trouble down the line.
402class SimulatorStack : public v8::internal::AllStatic {
403 public:
Ben Murdoch257744e2011-11-30 15:57:28 +0000404 static inline uintptr_t JsLimitFromCLimit(Isolate* isolate,
405 uintptr_t c_limit) {
406 return Simulator::current(isolate)->StackLimit();
Andrei Popescu31002712010-02-23 13:46:05 +0000407 }
408
409 static inline uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) {
Steve Block44f0eee2011-05-26 01:26:41 +0100410 Simulator* sim = Simulator::current(Isolate::Current());
Andrei Popescu31002712010-02-23 13:46:05 +0000411 return sim->PushAddress(try_catch_address);
412 }
413
414 static inline void UnregisterCTryCatch() {
Steve Block44f0eee2011-05-26 01:26:41 +0100415 Simulator::current(Isolate::Current())->PopAddress();
Andrei Popescu31002712010-02-23 13:46:05 +0000416 }
417};
418
Steve Block44f0eee2011-05-26 01:26:41 +0100419} } // namespace v8::internal
Andrei Popescu31002712010-02-23 13:46:05 +0000420
Steve Block44f0eee2011-05-26 01:26:41 +0100421#endif // !defined(USE_SIMULATOR)
Andrei Popescu31002712010-02-23 13:46:05 +0000422#endif // V8_MIPS_SIMULATOR_MIPS_H_