blob: 0cd9bbe75ca62b100842c818dacaed5a935839e8 [file] [log] [blame]
Andrei Popescu31002712010-02-23 13:46:05 +00001// Copyright 2010 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 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*,
53 void*, int*, Address, int, Isolate*);
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) \
60 (FUNCTION_CAST<mips_regexp_matcher>(entry)( \
61 p0, p1, p2, p3, NULL, p4, p5, p6, p7))
62
63#define TRY_CATCH_FROM_ADDRESS(try_catch_address) \
64 reinterpret_cast<TryCatch*>(try_catch_address)
Andrei Popescu31002712010-02-23 13:46:05 +000065
66// The stack limit beyond which we will throw stack overflow errors in
67// generated code. Because generated code on mips uses the C stack, we
68// just use the C stack limit.
69class SimulatorStack : public v8::internal::AllStatic {
70 public:
71 static inline uintptr_t JsLimitFromCLimit(uintptr_t c_limit) {
72 return c_limit;
73 }
74
75 static inline uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) {
76 return try_catch_address;
77 }
78
79 static inline void UnregisterCTryCatch() { }
80};
81
Steve Block44f0eee2011-05-26 01:26:41 +010082} } // namespace v8::internal
83
Andrei Popescu31002712010-02-23 13:46:05 +000084// Calculated the stack limit beyond which we will throw stack overflow errors.
85// This macro must be called from a C++ method. It relies on being able to take
86// the address of "this" to get a value on the current execution stack and then
87// calculates the stack limit based on that value.
88// NOTE: The check for overflow is not safe as there is no guarantee that the
89// running thread has its stack in all memory up to address 0x00000000.
90#define GENERATED_CODE_STACK_LIMIT(limit) \
91 (reinterpret_cast<uintptr_t>(this) >= limit ? \
92 reinterpret_cast<uintptr_t>(this) - limit : 0)
93
Steve Block44f0eee2011-05-26 01:26:41 +010094#else // !defined(USE_SIMULATOR)
95// Running with a simulator.
Andrei Popescu31002712010-02-23 13:46:05 +000096
Steve Block44f0eee2011-05-26 01:26:41 +010097#include "hashmap.h"
Andrei Popescu31002712010-02-23 13:46:05 +000098
Steve Block44f0eee2011-05-26 01:26:41 +010099namespace v8 {
100namespace internal {
Andrei Popescu31002712010-02-23 13:46:05 +0000101
Steve Block44f0eee2011-05-26 01:26:41 +0100102// -----------------------------------------------------------------------------
103// Utility functions
Andrei Popescu31002712010-02-23 13:46:05 +0000104
Steve Block44f0eee2011-05-26 01:26:41 +0100105class CachePage {
106 public:
107 static const int LINE_VALID = 0;
108 static const int LINE_INVALID = 1;
Andrei Popescu31002712010-02-23 13:46:05 +0000109
Steve Block44f0eee2011-05-26 01:26:41 +0100110 static const int kPageShift = 12;
111 static const int kPageSize = 1 << kPageShift;
112 static const int kPageMask = kPageSize - 1;
113 static const int kLineShift = 2; // The cache line is only 4 bytes right now.
114 static const int kLineLength = 1 << kLineShift;
115 static const int kLineMask = kLineLength - 1;
Andrei Popescu31002712010-02-23 13:46:05 +0000116
Steve Block44f0eee2011-05-26 01:26:41 +0100117 CachePage() {
118 memset(&validity_map_, LINE_INVALID, sizeof(validity_map_));
119 }
Andrei Popescu31002712010-02-23 13:46:05 +0000120
Steve Block44f0eee2011-05-26 01:26:41 +0100121 char* ValidityByte(int offset) {
122 return &validity_map_[offset >> kLineShift];
123 }
Andrei Popescu31002712010-02-23 13:46:05 +0000124
Steve Block44f0eee2011-05-26 01:26:41 +0100125 char* CachedData(int offset) {
126 return &data_[offset];
127 }
128
129 private:
130 char data_[kPageSize]; // The cached data.
131 static const int kValidityMapSize = kPageSize >> kLineShift;
132 char validity_map_[kValidityMapSize]; // One byte per line.
133};
Andrei Popescu31002712010-02-23 13:46:05 +0000134
135class Simulator {
136 public:
Steve Block44f0eee2011-05-26 01:26:41 +0100137 friend class MipsDebugger;
Andrei Popescu31002712010-02-23 13:46:05 +0000138
139 // Registers are declared in order. See SMRL chapter 2.
140 enum Register {
141 no_reg = -1,
142 zero_reg = 0,
143 at,
144 v0, v1,
145 a0, a1, a2, a3,
146 t0, t1, t2, t3, t4, t5, t6, t7,
147 s0, s1, s2, s3, s4, s5, s6, s7,
148 t8, t9,
149 k0, k1,
150 gp,
151 sp,
152 s8,
153 ra,
154 // LO, HI, and pc
155 LO,
156 HI,
157 pc, // pc must be the last register.
158 kNumSimuRegisters,
159 // aliases
160 fp = s8
161 };
162
163 // Coprocessor registers.
164 // Generated code will always use doubles. So we will only use even registers.
165 enum FPURegister {
166 f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11,
167 f12, f13, f14, f15, // f12 and f14 are arguments FPURegisters
168 f16, f17, f18, f19, f20, f21, f22, f23, f24, f25,
169 f26, f27, f28, f29, f30, f31,
170 kNumFPURegisters
171 };
172
173 Simulator();
174 ~Simulator();
175
176 // The currently executing Simulator instance. Potentially there can be one
177 // for each native thread.
Steve Block44f0eee2011-05-26 01:26:41 +0100178 static Simulator* current(v8::internal::Isolate* isolate);
Andrei Popescu31002712010-02-23 13:46:05 +0000179
180 // Accessors for register state. Reading the pc value adheres to the MIPS
181 // architecture specification and is off by a 8 from the currently executing
182 // instruction.
183 void set_register(int reg, int32_t value);
184 int32_t get_register(int reg) const;
185 // Same for FPURegisters
186 void set_fpu_register(int fpureg, int32_t value);
Steve Block44f0eee2011-05-26 01:26:41 +0100187 void set_fpu_register_float(int fpureg, float value);
Andrei Popescu31002712010-02-23 13:46:05 +0000188 void set_fpu_register_double(int fpureg, double value);
189 int32_t get_fpu_register(int fpureg) const;
Steve Block44f0eee2011-05-26 01:26:41 +0100190 int64_t get_fpu_register_long(int fpureg) const;
191 float get_fpu_register_float(int fpureg) const;
Andrei Popescu31002712010-02-23 13:46:05 +0000192 double get_fpu_register_double(int fpureg) const;
Steve Block44f0eee2011-05-26 01:26:41 +0100193 void set_fcsr_bit(uint32_t cc, bool value);
194 bool test_fcsr_bit(uint32_t cc);
195 bool set_fcsr_round_error(double original, double rounded);
Andrei Popescu31002712010-02-23 13:46:05 +0000196
197 // Special case of set_register and get_register to access the raw PC value.
198 void set_pc(int32_t value);
199 int32_t get_pc() const;
200
201 // Accessor to the internal simulator stack area.
202 uintptr_t StackLimit() const;
203
204 // Executes MIPS instructions until the PC reaches end_sim_pc.
205 void Execute();
206
207 // Call on program start.
208 static void Initialize();
209
210 // V8 generally calls into generated JS code with 5 parameters and into
211 // generated RegExp code with 7 parameters. This is a convenience function,
212 // which sets up the simulator state and grabs the result on return.
Steve Block44f0eee2011-05-26 01:26:41 +0100213 int32_t Call(byte* entry, int argument_count, ...);
Andrei Popescu31002712010-02-23 13:46:05 +0000214
215 // Push an address onto the JS stack.
216 uintptr_t PushAddress(uintptr_t address);
217
218 // Pop an address from the JS stack.
219 uintptr_t PopAddress();
220
Steve Block44f0eee2011-05-26 01:26:41 +0100221 // ICache checking.
222 static void FlushICache(v8::internal::HashMap* i_cache, void* start,
223 size_t size);
224
225 // Returns true if pc register contains one of the 'special_values' defined
226 // below (bad_ra, end_sim_pc).
227 bool has_bad_pc() const;
228
Andrei Popescu31002712010-02-23 13:46:05 +0000229 private:
230 enum special_values {
231 // Known bad pc value to ensure that the simulator does not execute
232 // without being properly setup.
233 bad_ra = -1,
234 // A pc value used to signal the simulator to stop execution. Generally
235 // the ra is set to this value on transition from native C code to
236 // simulated execution, so that the simulator can "return" to the native
237 // C code.
238 end_sim_pc = -2,
239 // Unpredictable value.
240 Unpredictable = 0xbadbeaf
241 };
242
243 // Unsupported instructions use Format to print an error and stop execution.
244 void Format(Instruction* instr, const char* format);
245
246 // Read and write memory.
247 inline uint32_t ReadBU(int32_t addr);
248 inline int32_t ReadB(int32_t addr);
249 inline void WriteB(int32_t addr, uint8_t value);
250 inline void WriteB(int32_t addr, int8_t value);
251
252 inline uint16_t ReadHU(int32_t addr, Instruction* instr);
253 inline int16_t ReadH(int32_t addr, Instruction* instr);
254 // Note: Overloaded on the sign of the value.
255 inline void WriteH(int32_t addr, uint16_t value, Instruction* instr);
256 inline void WriteH(int32_t addr, int16_t value, Instruction* instr);
257
258 inline int ReadW(int32_t addr, Instruction* instr);
259 inline void WriteW(int32_t addr, int value, Instruction* instr);
260
261 inline double ReadD(int32_t addr, Instruction* instr);
262 inline void WriteD(int32_t addr, double value, Instruction* instr);
263
264 // Operations depending on endianness.
265 // Get Double Higher / Lower word.
266 inline int32_t GetDoubleHIW(double* addr);
267 inline int32_t GetDoubleLOW(double* addr);
268 // Set Double Higher / Lower word.
269 inline int32_t SetDoubleHIW(double* addr);
270 inline int32_t SetDoubleLOW(double* addr);
271
Andrei Popescu31002712010-02-23 13:46:05 +0000272 // Executing is handled based on the instruction type.
273 void DecodeTypeRegister(Instruction* instr);
Steve Block44f0eee2011-05-26 01:26:41 +0100274
275 // Helper function for DecodeTypeRegister.
276 void ConfigureTypeRegister(Instruction* instr,
277 int32_t& alu_out,
278 int64_t& i64hilo,
279 uint64_t& u64hilo,
280 int32_t& next_pc,
281 bool& do_interrupt);
282
Andrei Popescu31002712010-02-23 13:46:05 +0000283 void DecodeTypeImmediate(Instruction* instr);
284 void DecodeTypeJump(Instruction* instr);
285
286 // Used for breakpoints and traps.
287 void SoftwareInterrupt(Instruction* instr);
288
289 // Executes one instruction.
290 void InstructionDecode(Instruction* instr);
291 // Execute one instruction placed in a branch delay slot.
292 void BranchDelayInstructionDecode(Instruction* instr) {
293 if (instr->IsForbiddenInBranchDelay()) {
294 V8_Fatal(__FILE__, __LINE__,
295 "Eror:Unexpected %i opcode in a branch delay slot.",
Steve Block44f0eee2011-05-26 01:26:41 +0100296 instr->OpcodeValue());
Andrei Popescu31002712010-02-23 13:46:05 +0000297 }
298 InstructionDecode(instr);
299 }
300
Steve Block44f0eee2011-05-26 01:26:41 +0100301 // ICache.
302 static void CheckICache(v8::internal::HashMap* i_cache, Instruction* instr);
303 static void FlushOnePage(v8::internal::HashMap* i_cache, intptr_t start,
304 int size);
305 static CachePage* GetCachePage(v8::internal::HashMap* i_cache, void* page);
306
307
Andrei Popescu31002712010-02-23 13:46:05 +0000308 enum Exception {
309 none,
310 kIntegerOverflow,
311 kIntegerUnderflow,
312 kDivideByZero,
313 kNumExceptions
314 };
315 int16_t exceptions[kNumExceptions];
316
317 // Exceptions.
318 void SignalExceptions();
319
320 // Runtime call support.
321 static void* RedirectExternalReference(void* external_function,
Steve Block44f0eee2011-05-26 01:26:41 +0100322 ExternalReference::Type type);
Andrei Popescu31002712010-02-23 13:46:05 +0000323
324 // Used for real time calls that takes two double values as arguments and
325 // returns a double.
326 void SetFpResult(double result);
327
328 // Architecture state.
329 // Registers.
330 int32_t registers_[kNumSimuRegisters];
331 // Coprocessor Registers.
332 int32_t FPUregisters_[kNumFPURegisters];
Steve Block44f0eee2011-05-26 01:26:41 +0100333 // FPU control register.
334 uint32_t FCSR_;
Andrei Popescu31002712010-02-23 13:46:05 +0000335
336 // Simulator support.
337 char* stack_;
Steve Block44f0eee2011-05-26 01:26:41 +0100338 size_t stack_size_;
Andrei Popescu31002712010-02-23 13:46:05 +0000339 bool pc_modified_;
340 int icount_;
Steve Block44f0eee2011-05-26 01:26:41 +0100341 int break_count_;
342
343 // Icache simulation
344 v8::internal::HashMap* i_cache_;
Andrei Popescu31002712010-02-23 13:46:05 +0000345
346 // Registered breakpoints.
347 Instruction* break_pc_;
348 Instr break_instr_;
Steve Block44f0eee2011-05-26 01:26:41 +0100349
350 v8::internal::Isolate* isolate_;
Andrei Popescu31002712010-02-23 13:46:05 +0000351};
352
Steve Block44f0eee2011-05-26 01:26:41 +0100353
354// When running with the simulator transition into simulated execution at this
355// point.
356#define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \
357reinterpret_cast<Object*>(Simulator::current(Isolate::Current())->Call( \
358 FUNCTION_ADDR(entry), 5, p0, p1, p2, p3, p4))
359
360#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7) \
361 Simulator::current(Isolate::Current())->Call( \
362 entry, 9, p0, p1, p2, p3, NULL, p4, p5, p6, p7)
363
364#define TRY_CATCH_FROM_ADDRESS(try_catch_address) \
365 try_catch_address == NULL ? \
366 NULL : *(reinterpret_cast<TryCatch**>(try_catch_address))
Andrei Popescu31002712010-02-23 13:46:05 +0000367
368
369// The simulator has its own stack. Thus it has a different stack limit from
370// the C-based native code. Setting the c_limit to indicate a very small
371// stack cause stack overflow errors, since the simulator ignores the input.
372// This is unlikely to be an issue in practice, though it might cause testing
373// trouble down the line.
374class SimulatorStack : public v8::internal::AllStatic {
375 public:
376 static inline uintptr_t JsLimitFromCLimit(uintptr_t c_limit) {
Steve Block44f0eee2011-05-26 01:26:41 +0100377 return Simulator::current(Isolate::Current())->StackLimit();
Andrei Popescu31002712010-02-23 13:46:05 +0000378 }
379
380 static inline uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) {
Steve Block44f0eee2011-05-26 01:26:41 +0100381 Simulator* sim = Simulator::current(Isolate::Current());
Andrei Popescu31002712010-02-23 13:46:05 +0000382 return sim->PushAddress(try_catch_address);
383 }
384
385 static inline void UnregisterCTryCatch() {
Steve Block44f0eee2011-05-26 01:26:41 +0100386 Simulator::current(Isolate::Current())->PopAddress();
Andrei Popescu31002712010-02-23 13:46:05 +0000387 }
388};
389
Steve Block44f0eee2011-05-26 01:26:41 +0100390} } // namespace v8::internal
Andrei Popescu31002712010-02-23 13:46:05 +0000391
Steve Block44f0eee2011-05-26 01:26:41 +0100392#endif // !defined(USE_SIMULATOR)
Andrei Popescu31002712010-02-23 13:46:05 +0000393#endif // V8_MIPS_SIMULATOR_MIPS_H_
394