blob: 1e729398760e2c099f90f9bc3b05a9d4ff154ed0 [file] [log] [blame]
Ben Murdoch257744e2011-11-30 15:57:28 +00001// Copyright 2011 the V8 project authors. All rights reserved.
Andrei Popescu31002712010-02-23 13:46:05 +00002// 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 MIPS instructions if we are not generating a native
30// MIPS binary. This Simulator allows us to run and debug MIPS code generation
31// on 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 MIPS HW platform.
35
36#ifndef V8_MIPS_SIMULATOR_MIPS_H_
37#define V8_MIPS_SIMULATOR_MIPS_H_
38
39#include "allocation.h"
Steve Block44f0eee2011-05-26 01:26:41 +010040#include "constants-mips.h"
Andrei Popescu31002712010-02-23 13:46:05 +000041
Steve Block44f0eee2011-05-26 01:26:41 +010042#if !defined(USE_SIMULATOR)
43// Running without a simulator on a native mips platform.
44
45namespace v8 {
46namespace internal {
Andrei Popescu31002712010-02-23 13:46:05 +000047
48// When running without a simulator we call the entry directly.
49#define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \
Steve Block44f0eee2011-05-26 01:26:41 +010050 entry(p0, p1, p2, p3, p4)
51
52typedef int (*mips_regexp_matcher)(String*, int, const byte*, const byte*,
Ben Murdoch257744e2011-11-30 15:57:28 +000053 void*, int*, Address, int, Isolate*);
54
Steve Block44f0eee2011-05-26 01:26:41 +010055
56// Call the generated regexp code directly. The code at the entry address
57// should act as a function matching the type arm_regexp_matcher.
58// The fifth argument is a dummy that reserves the space used for
59// 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) \
Ben Murdoch257744e2011-11-30 15:57:28 +000061 (FUNCTION_CAST<mips_regexp_matcher>(entry)( \
Steve Block44f0eee2011-05-26 01:26:41 +010062 p0, p1, p2, p3, NULL, p4, p5, p6, p7))
63
64#define TRY_CATCH_FROM_ADDRESS(try_catch_address) \
65 reinterpret_cast<TryCatch*>(try_catch_address)
Andrei Popescu31002712010-02-23 13:46:05 +000066
67// The stack limit beyond which we will throw stack overflow errors in
68// generated code. Because generated code on mips uses the C stack, we
69// just use the C stack limit.
70class SimulatorStack : public v8::internal::AllStatic {
71 public:
Ben Murdoch257744e2011-11-30 15:57:28 +000072 static inline uintptr_t JsLimitFromCLimit(Isolate* isolate,
73 uintptr_t c_limit) {
Andrei Popescu31002712010-02-23 13:46:05 +000074 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
Steve Block44f0eee2011-05-26 01:26:41 +010084} } // namespace v8::internal
85
Andrei Popescu31002712010-02-23 13:46:05 +000086// Calculated the stack limit beyond which we will throw stack overflow errors.
87// This macro must be called from a C++ method. It relies on being able to take
88// the address of "this" to get a value on the current execution stack and then
89// calculates the stack limit based on that value.
90// NOTE: The check for overflow is not safe as there is no guarantee that the
91// running thread has its stack in all memory up to address 0x00000000.
92#define GENERATED_CODE_STACK_LIMIT(limit) \
93 (reinterpret_cast<uintptr_t>(this) >= limit ? \
94 reinterpret_cast<uintptr_t>(this) - limit : 0)
95
Steve Block44f0eee2011-05-26 01:26:41 +010096#else // !defined(USE_SIMULATOR)
97// Running with a simulator.
Andrei Popescu31002712010-02-23 13:46:05 +000098
Steve Block44f0eee2011-05-26 01:26:41 +010099#include "hashmap.h"
Ben Murdoch257744e2011-11-30 15:57:28 +0000100#include "assembler.h"
Andrei Popescu31002712010-02-23 13:46:05 +0000101
Steve Block44f0eee2011-05-26 01:26:41 +0100102namespace v8 {
103namespace internal {
Andrei Popescu31002712010-02-23 13:46:05 +0000104
Steve Block44f0eee2011-05-26 01:26:41 +0100105// -----------------------------------------------------------------------------
106// Utility functions
Andrei Popescu31002712010-02-23 13:46:05 +0000107
Steve Block44f0eee2011-05-26 01:26:41 +0100108class CachePage {
109 public:
110 static const int LINE_VALID = 0;
111 static const int LINE_INVALID = 1;
Andrei Popescu31002712010-02-23 13:46:05 +0000112
Steve Block44f0eee2011-05-26 01:26:41 +0100113 static const int kPageShift = 12;
114 static const int kPageSize = 1 << kPageShift;
115 static const int kPageMask = kPageSize - 1;
116 static const int kLineShift = 2; // The cache line is only 4 bytes right now.
117 static const int kLineLength = 1 << kLineShift;
118 static const int kLineMask = kLineLength - 1;
Andrei Popescu31002712010-02-23 13:46:05 +0000119
Steve Block44f0eee2011-05-26 01:26:41 +0100120 CachePage() {
121 memset(&validity_map_, LINE_INVALID, sizeof(validity_map_));
122 }
Andrei Popescu31002712010-02-23 13:46:05 +0000123
Steve Block44f0eee2011-05-26 01:26:41 +0100124 char* ValidityByte(int offset) {
125 return &validity_map_[offset >> kLineShift];
126 }
Andrei Popescu31002712010-02-23 13:46:05 +0000127
Steve Block44f0eee2011-05-26 01:26:41 +0100128 char* CachedData(int offset) {
129 return &data_[offset];
130 }
131
132 private:
133 char data_[kPageSize]; // The cached data.
134 static const int kValidityMapSize = kPageSize >> kLineShift;
135 char validity_map_[kValidityMapSize]; // One byte per line.
136};
Andrei Popescu31002712010-02-23 13:46:05 +0000137
138class Simulator {
139 public:
Steve Block44f0eee2011-05-26 01:26:41 +0100140 friend class MipsDebugger;
Andrei Popescu31002712010-02-23 13:46:05 +0000141
142 // Registers are declared in order. See SMRL chapter 2.
143 enum Register {
144 no_reg = -1,
145 zero_reg = 0,
146 at,
147 v0, v1,
148 a0, a1, a2, a3,
149 t0, t1, t2, t3, t4, t5, t6, t7,
150 s0, s1, s2, s3, s4, s5, s6, s7,
151 t8, t9,
152 k0, k1,
153 gp,
154 sp,
155 s8,
156 ra,
Ben Murdoch257744e2011-11-30 15:57:28 +0000157 // LO, HI, and pc.
Andrei Popescu31002712010-02-23 13:46:05 +0000158 LO,
159 HI,
160 pc, // pc must be the last register.
161 kNumSimuRegisters,
162 // aliases
163 fp = s8
164 };
165
166 // Coprocessor registers.
167 // Generated code will always use doubles. So we will only use even registers.
168 enum FPURegister {
169 f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11,
Ben Murdoch257744e2011-11-30 15:57:28 +0000170 f12, f13, f14, f15, // f12 and f14 are arguments FPURegisters.
Andrei Popescu31002712010-02-23 13:46:05 +0000171 f16, f17, f18, f19, f20, f21, f22, f23, f24, f25,
172 f26, f27, f28, f29, f30, f31,
173 kNumFPURegisters
174 };
175
Ben Murdoch257744e2011-11-30 15:57:28 +0000176 explicit Simulator(Isolate* isolate);
Andrei Popescu31002712010-02-23 13:46:05 +0000177 ~Simulator();
178
179 // The currently executing Simulator instance. Potentially there can be one
180 // for each native thread.
Steve Block44f0eee2011-05-26 01:26:41 +0100181 static Simulator* current(v8::internal::Isolate* isolate);
Andrei Popescu31002712010-02-23 13:46:05 +0000182
183 // Accessors for register state. Reading the pc value adheres to the MIPS
184 // architecture specification and is off by a 8 from the currently executing
185 // instruction.
186 void set_register(int reg, int32_t value);
187 int32_t get_register(int reg) const;
Ben Murdoch257744e2011-11-30 15:57:28 +0000188 // Same for FPURegisters.
Andrei Popescu31002712010-02-23 13:46:05 +0000189 void set_fpu_register(int fpureg, int32_t value);
Steve Block44f0eee2011-05-26 01:26:41 +0100190 void set_fpu_register_float(int fpureg, float value);
Andrei Popescu31002712010-02-23 13:46:05 +0000191 void set_fpu_register_double(int fpureg, double value);
192 int32_t get_fpu_register(int fpureg) const;
Steve Block44f0eee2011-05-26 01:26:41 +0100193 int64_t get_fpu_register_long(int fpureg) const;
194 float get_fpu_register_float(int fpureg) const;
Andrei Popescu31002712010-02-23 13:46:05 +0000195 double get_fpu_register_double(int fpureg) const;
Steve Block44f0eee2011-05-26 01:26:41 +0100196 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);
Andrei Popescu31002712010-02-23 13:46:05 +0000199
200 // Special case of set_register and get_register to access the raw PC value.
201 void set_pc(int32_t value);
202 int32_t get_pc() const;
203
204 // Accessor to the internal simulator stack area.
205 uintptr_t StackLimit() const;
206
207 // Executes MIPS instructions until the PC reaches end_sim_pc.
208 void Execute();
209
210 // Call on program start.
Ben Murdoch257744e2011-11-30 15:57:28 +0000211 static void Initialize(Isolate* isolate);
Andrei Popescu31002712010-02-23 13:46:05 +0000212
213 // V8 generally calls into generated JS code with 5 parameters and into
214 // generated RegExp code with 7 parameters. This is a convenience function,
215 // which sets up the simulator state and grabs the result on return.
Steve Block44f0eee2011-05-26 01:26:41 +0100216 int32_t Call(byte* entry, int argument_count, ...);
Andrei Popescu31002712010-02-23 13:46:05 +0000217
218 // Push an address onto the JS stack.
219 uintptr_t PushAddress(uintptr_t address);
220
221 // Pop an address from the JS stack.
222 uintptr_t PopAddress();
223
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100224 // Debugger input.
225 void set_last_debugger_input(char* input);
226 char* last_debugger_input() { return last_debugger_input_; }
227
Steve Block44f0eee2011-05-26 01:26:41 +0100228 // ICache checking.
229 static void FlushICache(v8::internal::HashMap* i_cache, void* start,
230 size_t size);
231
232 // Returns true if pc register contains one of the 'special_values' defined
233 // below (bad_ra, end_sim_pc).
234 bool has_bad_pc() const;
235
Andrei Popescu31002712010-02-23 13:46:05 +0000236 private:
237 enum special_values {
238 // Known bad pc value to ensure that the simulator does not execute
239 // without being properly setup.
240 bad_ra = -1,
241 // A pc value used to signal the simulator to stop execution. Generally
242 // the ra is set to this value on transition from native C code to
243 // simulated execution, so that the simulator can "return" to the native
244 // C code.
245 end_sim_pc = -2,
246 // Unpredictable value.
247 Unpredictable = 0xbadbeaf
248 };
249
250 // Unsupported instructions use Format to print an error and stop execution.
251 void Format(Instruction* instr, const char* format);
252
253 // Read and write memory.
254 inline uint32_t ReadBU(int32_t addr);
255 inline int32_t ReadB(int32_t addr);
256 inline void WriteB(int32_t addr, uint8_t value);
257 inline void WriteB(int32_t addr, int8_t value);
258
259 inline uint16_t ReadHU(int32_t addr, Instruction* instr);
260 inline int16_t ReadH(int32_t addr, Instruction* instr);
261 // Note: Overloaded on the sign of the value.
262 inline void WriteH(int32_t addr, uint16_t value, Instruction* instr);
263 inline void WriteH(int32_t addr, int16_t value, Instruction* instr);
264
265 inline int ReadW(int32_t addr, Instruction* instr);
266 inline void WriteW(int32_t addr, int value, Instruction* instr);
267
268 inline double ReadD(int32_t addr, Instruction* instr);
269 inline void WriteD(int32_t addr, double value, Instruction* instr);
270
271 // Operations depending on endianness.
272 // Get Double Higher / Lower word.
273 inline int32_t GetDoubleHIW(double* addr);
274 inline int32_t GetDoubleLOW(double* addr);
275 // Set Double Higher / Lower word.
276 inline int32_t SetDoubleHIW(double* addr);
277 inline int32_t SetDoubleLOW(double* addr);
278
Andrei Popescu31002712010-02-23 13:46:05 +0000279 // Executing is handled based on the instruction type.
280 void DecodeTypeRegister(Instruction* instr);
Steve Block44f0eee2011-05-26 01:26:41 +0100281
282 // Helper function for DecodeTypeRegister.
283 void ConfigureTypeRegister(Instruction* instr,
284 int32_t& alu_out,
285 int64_t& i64hilo,
286 uint64_t& u64hilo,
287 int32_t& next_pc,
288 bool& do_interrupt);
289
Andrei Popescu31002712010-02-23 13:46:05 +0000290 void DecodeTypeImmediate(Instruction* instr);
291 void DecodeTypeJump(Instruction* instr);
292
293 // Used for breakpoints and traps.
294 void SoftwareInterrupt(Instruction* instr);
295
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000296 // Stop helper functions.
297 bool IsWatchpoint(uint32_t code);
298 void PrintWatchpoint(uint32_t code);
299 void HandleStop(uint32_t code, Instruction* instr);
300 bool IsStopInstruction(Instruction* instr);
301 bool IsEnabledStop(uint32_t code);
302 void EnableStop(uint32_t code);
303 void DisableStop(uint32_t code);
304 void IncreaseStopCounter(uint32_t code);
305 void PrintStopInfo(uint32_t code);
306
307
Andrei Popescu31002712010-02-23 13:46:05 +0000308 // Executes one instruction.
309 void InstructionDecode(Instruction* instr);
310 // Execute one instruction placed in a branch delay slot.
311 void BranchDelayInstructionDecode(Instruction* instr) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100312 if (instr->InstructionBits() == nopInstr) {
313 // Short-cut generic nop instructions. They are always valid and they
314 // never change the simulator state.
315 set_register(pc, reinterpret_cast<int32_t>(instr) +
316 Instruction::kInstrSize);
317 return;
318 }
319
Andrei Popescu31002712010-02-23 13:46:05 +0000320 if (instr->IsForbiddenInBranchDelay()) {
321 V8_Fatal(__FILE__, __LINE__,
322 "Eror:Unexpected %i opcode in a branch delay slot.",
Steve Block44f0eee2011-05-26 01:26:41 +0100323 instr->OpcodeValue());
Andrei Popescu31002712010-02-23 13:46:05 +0000324 }
325 InstructionDecode(instr);
326 }
327
Steve Block44f0eee2011-05-26 01:26:41 +0100328 // ICache.
329 static void CheckICache(v8::internal::HashMap* i_cache, Instruction* instr);
330 static void FlushOnePage(v8::internal::HashMap* i_cache, intptr_t start,
331 int size);
332 static CachePage* GetCachePage(v8::internal::HashMap* i_cache, void* page);
333
Andrei Popescu31002712010-02-23 13:46:05 +0000334 enum Exception {
335 none,
336 kIntegerOverflow,
337 kIntegerUnderflow,
338 kDivideByZero,
339 kNumExceptions
340 };
341 int16_t exceptions[kNumExceptions];
342
343 // Exceptions.
344 void SignalExceptions();
345
346 // Runtime call support.
347 static void* RedirectExternalReference(void* external_function,
Steve Block44f0eee2011-05-26 01:26:41 +0100348 ExternalReference::Type type);
Andrei Popescu31002712010-02-23 13:46:05 +0000349
Ben Murdoch257744e2011-11-30 15:57:28 +0000350 // For use in calls that take double value arguments.
351 void GetFpArgs(double* x, double* y);
352 void GetFpArgs(double* x);
353 void GetFpArgs(double* x, int32_t* y);
354 void SetFpResult(const double& result);
355
Andrei Popescu31002712010-02-23 13:46:05 +0000356
357 // Architecture state.
358 // Registers.
359 int32_t registers_[kNumSimuRegisters];
360 // Coprocessor Registers.
361 int32_t FPUregisters_[kNumFPURegisters];
Steve Block44f0eee2011-05-26 01:26:41 +0100362 // FPU control register.
363 uint32_t FCSR_;
Andrei Popescu31002712010-02-23 13:46:05 +0000364
365 // Simulator support.
Ben Murdoch257744e2011-11-30 15:57:28 +0000366 // Allocate 1MB for stack.
367 static const size_t stack_size_ = 1 * 1024*1024;
Andrei Popescu31002712010-02-23 13:46:05 +0000368 char* stack_;
369 bool pc_modified_;
370 int icount_;
Steve Block44f0eee2011-05-26 01:26:41 +0100371 int break_count_;
372
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100373 // Debugger input.
374 char* last_debugger_input_;
375
Ben Murdoch257744e2011-11-30 15:57:28 +0000376 // Icache simulation.
Steve Block44f0eee2011-05-26 01:26:41 +0100377 v8::internal::HashMap* i_cache_;
Andrei Popescu31002712010-02-23 13:46:05 +0000378
Ben Murdoch257744e2011-11-30 15:57:28 +0000379 v8::internal::Isolate* isolate_;
380
Andrei Popescu31002712010-02-23 13:46:05 +0000381 // Registered breakpoints.
382 Instruction* break_pc_;
383 Instr break_instr_;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000384
385 // Stop is disabled if bit 31 is set.
386 static const uint32_t kStopDisabledBit = 1 << 31;
387
388 // A stop is enabled, meaning the simulator will stop when meeting the
389 // instruction, if bit 31 of watched_stops[code].count is unset.
390 // The value watched_stops[code].count & ~(1 << 31) indicates how many times
391 // the breakpoint was hit or gone through.
392 struct StopCountAndDesc {
393 uint32_t count;
394 char* desc;
395 };
396 StopCountAndDesc watched_stops[kMaxStopCode + 1];
Andrei Popescu31002712010-02-23 13:46:05 +0000397};
398
Steve Block44f0eee2011-05-26 01:26:41 +0100399
400// When running with the simulator transition into simulated execution at this
401// point.
402#define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \
Ben Murdoch257744e2011-11-30 15:57:28 +0000403 reinterpret_cast<Object*>(Simulator::current(Isolate::Current())->Call( \
Steve Block44f0eee2011-05-26 01:26:41 +0100404 FUNCTION_ADDR(entry), 5, p0, p1, p2, p3, p4))
405
406#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7) \
Ben Murdoch257744e2011-11-30 15:57:28 +0000407 Simulator::current(Isolate::Current())->Call( \
408 entry, 9, p0, p1, p2, p3, NULL, p4, p5, p6, p7)
Steve Block44f0eee2011-05-26 01:26:41 +0100409
Ben Murdoch257744e2011-11-30 15:57:28 +0000410#define TRY_CATCH_FROM_ADDRESS(try_catch_address) \
411 try_catch_address == NULL ? \
Steve Block44f0eee2011-05-26 01:26:41 +0100412 NULL : *(reinterpret_cast<TryCatch**>(try_catch_address))
Andrei Popescu31002712010-02-23 13:46:05 +0000413
414
415// The simulator has its own stack. Thus it has a different stack limit from
416// the C-based native code. Setting the c_limit to indicate a very small
417// stack cause stack overflow errors, since the simulator ignores the input.
418// This is unlikely to be an issue in practice, though it might cause testing
419// trouble down the line.
420class SimulatorStack : public v8::internal::AllStatic {
421 public:
Ben Murdoch257744e2011-11-30 15:57:28 +0000422 static inline uintptr_t JsLimitFromCLimit(Isolate* isolate,
423 uintptr_t c_limit) {
424 return Simulator::current(isolate)->StackLimit();
Andrei Popescu31002712010-02-23 13:46:05 +0000425 }
426
427 static inline uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) {
Steve Block44f0eee2011-05-26 01:26:41 +0100428 Simulator* sim = Simulator::current(Isolate::Current());
Andrei Popescu31002712010-02-23 13:46:05 +0000429 return sim->PushAddress(try_catch_address);
430 }
431
432 static inline void UnregisterCTryCatch() {
Steve Block44f0eee2011-05-26 01:26:41 +0100433 Simulator::current(Isolate::Current())->PopAddress();
Andrei Popescu31002712010-02-23 13:46:05 +0000434 }
435};
436
Steve Block44f0eee2011-05-26 01:26:41 +0100437} } // namespace v8::internal
Andrei Popescu31002712010-02-23 13:46:05 +0000438
Steve Block44f0eee2011-05-26 01:26:41 +0100439#endif // !defined(USE_SIMULATOR)
Andrei Popescu31002712010-02-23 13:46:05 +0000440#endif // V8_MIPS_SIMULATOR_MIPS_H_