OLD | NEW |
| (Empty) |
1 // Copyright 2013 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 #ifndef V8_A64_SIMULATOR_A64_H_ | |
29 #define V8_A64_SIMULATOR_A64_H_ | |
30 | |
31 #include <stdarg.h> | |
32 #include <vector> | |
33 | |
34 #include "v8.h" | |
35 | |
36 #include "globals.h" | |
37 #include "utils.h" | |
38 #include "allocation.h" | |
39 #include "assembler.h" | |
40 #include "a64/assembler-a64.h" | |
41 #include "a64/decoder-a64.h" | |
42 #include "a64/disasm-a64.h" | |
43 #include "a64/instrument-a64.h" | |
44 | |
45 #define REGISTER_CODE_LIST(R) \ | |
46 R(0) R(1) R(2) R(3) R(4) R(5) R(6) R(7) \ | |
47 R(8) R(9) R(10) R(11) R(12) R(13) R(14) R(15) \ | |
48 R(16) R(17) R(18) R(19) R(20) R(21) R(22) R(23) \ | |
49 R(24) R(25) R(26) R(27) R(28) R(29) R(30) R(31) | |
50 | |
51 namespace v8 { | |
52 namespace internal { | |
53 | |
54 #if !defined(USE_SIMULATOR) | |
55 | |
56 // Running without a simulator on a native A64 platform. | |
57 // When running without a simulator we call the entry directly. | |
58 #define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \ | |
59 (entry(p0, p1, p2, p3, p4)) | |
60 | |
61 typedef int (*a64_regexp_matcher)(String* input, | |
62 int64_t start_offset, | |
63 const byte* input_start, | |
64 const byte* input_end, | |
65 int* output, | |
66 int64_t output_size, | |
67 Address stack_base, | |
68 int64_t direct_call, | |
69 void* return_address, | |
70 Isolate* isolate); | |
71 | |
72 // Call the generated regexp code directly. The code at the entry address | |
73 // should act as a function matching the type a64_regexp_matcher. | |
74 // The ninth argument is a dummy that reserves the space used for | |
75 // the return address added by the ExitFrame in native calls. | |
76 #define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7, p8) \ | |
77 (FUNCTION_CAST<a64_regexp_matcher>(entry)( \ | |
78 p0, p1, p2, p3, p4, p5, p6, p7, NULL, p8)) | |
79 | |
80 #define TRY_CATCH_FROM_ADDRESS(try_catch_address) \ | |
81 reinterpret_cast<TryCatch*>(try_catch_address) | |
82 | |
83 // Running without a simulator there is nothing to do. | |
84 class SimulatorStack : public v8::internal::AllStatic { | |
85 public: | |
86 static uintptr_t JsLimitFromCLimit(v8::internal::Isolate* isolate, | |
87 uintptr_t c_limit) { | |
88 USE(isolate); | |
89 return c_limit; | |
90 } | |
91 | |
92 static uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) { | |
93 return try_catch_address; | |
94 } | |
95 | |
96 static void UnregisterCTryCatch() { } | |
97 }; | |
98 | |
99 #else // !defined(USE_SIMULATOR) | |
100 | |
101 enum ReverseByteMode { | |
102 Reverse16 = 0, | |
103 Reverse32 = 1, | |
104 Reverse64 = 2 | |
105 }; | |
106 | |
107 | |
108 // The proper way to initialize a simulated system register (such as NZCV) is as | |
109 // follows: | |
110 // SimSystemRegister nzcv = SimSystemRegister::DefaultValueFor(NZCV); | |
111 class SimSystemRegister { | |
112 public: | |
113 // The default constructor represents a register which has no writable bits. | |
114 // It is not possible to set its value to anything other than 0. | |
115 SimSystemRegister() : value_(0), write_ignore_mask_(0xffffffff) { } | |
116 | |
117 uint32_t RawValue() const { | |
118 return value_; | |
119 } | |
120 | |
121 void SetRawValue(uint32_t new_value) { | |
122 value_ = (value_ & write_ignore_mask_) | (new_value & ~write_ignore_mask_); | |
123 } | |
124 | |
125 uint32_t Bits(int msb, int lsb) const { | |
126 return unsigned_bitextract_32(msb, lsb, value_); | |
127 } | |
128 | |
129 int32_t SignedBits(int msb, int lsb) const { | |
130 return signed_bitextract_32(msb, lsb, value_); | |
131 } | |
132 | |
133 void SetBits(int msb, int lsb, uint32_t bits); | |
134 | |
135 // Default system register values. | |
136 static SimSystemRegister DefaultValueFor(SystemRegister id); | |
137 | |
138 #define DEFINE_GETTER(Name, HighBit, LowBit, Func, Type) \ | |
139 Type Name() const { return static_cast<Type>(Func(HighBit, LowBit)); } \ | |
140 void Set##Name(Type bits) { \ | |
141 SetBits(HighBit, LowBit, static_cast<Type>(bits)); \ | |
142 } | |
143 #define DEFINE_WRITE_IGNORE_MASK(Name, Mask) \ | |
144 static const uint32_t Name##WriteIgnoreMask = ~static_cast<uint32_t>(Mask); | |
145 SYSTEM_REGISTER_FIELDS_LIST(DEFINE_GETTER, DEFINE_WRITE_IGNORE_MASK) | |
146 #undef DEFINE_ZERO_BITS | |
147 #undef DEFINE_GETTER | |
148 | |
149 protected: | |
150 // Most system registers only implement a few of the bits in the word. Other | |
151 // bits are "read-as-zero, write-ignored". The write_ignore_mask argument | |
152 // describes the bits which are not modifiable. | |
153 SimSystemRegister(uint32_t value, uint32_t write_ignore_mask) | |
154 : value_(value), write_ignore_mask_(write_ignore_mask) { } | |
155 | |
156 uint32_t value_; | |
157 uint32_t write_ignore_mask_; | |
158 }; | |
159 | |
160 | |
161 // Represent a register (r0-r31, v0-v31). | |
162 template<int kSizeInBytes> | |
163 class SimRegisterBase { | |
164 public: | |
165 template<typename T> | |
166 void Set(T new_value, unsigned size = sizeof(T)) { | |
167 ASSERT(size <= kSizeInBytes); | |
168 ASSERT(size <= sizeof(new_value)); | |
169 // All AArch64 registers are zero-extending; Writing a W register clears the | |
170 // top bits of the corresponding X register. | |
171 memset(value_, 0, kSizeInBytes); | |
172 memcpy(value_, &new_value, size); | |
173 } | |
174 | |
175 // Copy 'size' bytes of the register to the result, and zero-extend to fill | |
176 // the result. | |
177 template<typename T> | |
178 T Get(unsigned size = sizeof(T)) const { | |
179 ASSERT(size <= kSizeInBytes); | |
180 T result; | |
181 memset(&result, 0, sizeof(result)); | |
182 memcpy(&result, value_, size); | |
183 return result; | |
184 } | |
185 | |
186 protected: | |
187 uint8_t value_[kSizeInBytes]; | |
188 }; | |
189 typedef SimRegisterBase<kXRegSize> SimRegister; // r0-r31 | |
190 typedef SimRegisterBase<kDRegSize> SimFPRegister; // v0-v31 | |
191 | |
192 | |
193 class Simulator : public DecoderVisitor { | |
194 public: | |
195 explicit Simulator(Decoder<DispatchingDecoderVisitor>* decoder, | |
196 Isolate* isolate = NULL, | |
197 FILE* stream = stderr); | |
198 Simulator(); | |
199 ~Simulator(); | |
200 | |
201 // System functions. | |
202 | |
203 static void Initialize(Isolate* isolate); | |
204 | |
205 static Simulator* current(v8::internal::Isolate* isolate); | |
206 | |
207 class CallArgument; | |
208 | |
209 // Call an arbitrary function taking an arbitrary number of arguments. The | |
210 // varargs list must be a set of arguments with type CallArgument, and | |
211 // terminated by CallArgument::End(). | |
212 void CallVoid(byte* entry, CallArgument* args); | |
213 | |
214 // Like CallVoid, but expect a return value. | |
215 int64_t CallInt64(byte* entry, CallArgument* args); | |
216 double CallDouble(byte* entry, CallArgument* args); | |
217 | |
218 // V8 calls into generated JS code with 5 parameters and into | |
219 // generated RegExp code with 10 parameters. These are convenience functions, | |
220 // which set up the simulator state and grab the result on return. | |
221 int64_t CallJS(byte* entry, | |
222 byte* function_entry, | |
223 JSFunction* func, | |
224 Object* revc, | |
225 int64_t argc, | |
226 Object*** argv); | |
227 int64_t CallRegExp(byte* entry, | |
228 String* input, | |
229 int64_t start_offset, | |
230 const byte* input_start, | |
231 const byte* input_end, | |
232 int* output, | |
233 int64_t output_size, | |
234 Address stack_base, | |
235 int64_t direct_call, | |
236 void* return_address, | |
237 Isolate* isolate); | |
238 | |
239 // A wrapper class that stores an argument for one of the above Call | |
240 // functions. | |
241 // | |
242 // Only arguments up to 64 bits in size are supported. | |
243 class CallArgument { | |
244 public: | |
245 template<typename T> | |
246 explicit CallArgument(T argument) { | |
247 ASSERT(sizeof(argument) <= sizeof(bits_)); | |
248 memcpy(&bits_, &argument, sizeof(argument)); | |
249 type_ = X_ARG; | |
250 } | |
251 | |
252 explicit CallArgument(double argument) { | |
253 ASSERT(sizeof(argument) == sizeof(bits_)); | |
254 memcpy(&bits_, &argument, sizeof(argument)); | |
255 type_ = D_ARG; | |
256 } | |
257 | |
258 explicit CallArgument(float argument) { | |
259 // TODO(all): CallArgument(float) is untested, remove this check once | |
260 // tested. | |
261 UNIMPLEMENTED(); | |
262 // Make the D register a NaN to try to trap errors if the callee expects a | |
263 // double. If it expects a float, the callee should ignore the top word. | |
264 ASSERT(sizeof(kFP64SignallingNaN) == sizeof(bits_)); | |
265 memcpy(&bits_, &kFP64SignallingNaN, sizeof(kFP64SignallingNaN)); | |
266 // Write the float payload to the S register. | |
267 ASSERT(sizeof(argument) <= sizeof(bits_)); | |
268 memcpy(&bits_, &argument, sizeof(argument)); | |
269 type_ = D_ARG; | |
270 } | |
271 | |
272 // This indicates the end of the arguments list, so that CallArgument | |
273 // objects can be passed into varargs functions. | |
274 static CallArgument End() { return CallArgument(); } | |
275 | |
276 int64_t bits() const { return bits_; } | |
277 bool IsEnd() const { return type_ == NO_ARG; } | |
278 bool IsX() const { return type_ == X_ARG; } | |
279 bool IsD() const { return type_ == D_ARG; } | |
280 | |
281 private: | |
282 enum CallArgumentType { X_ARG, D_ARG, NO_ARG }; | |
283 | |
284 // All arguments are aligned to at least 64 bits and we don't support | |
285 // passing bigger arguments, so the payload size can be fixed at 64 bits. | |
286 int64_t bits_; | |
287 CallArgumentType type_; | |
288 | |
289 CallArgument() { type_ = NO_ARG; } | |
290 }; | |
291 | |
292 | |
293 // Start the debugging command line. | |
294 void Debug(); | |
295 | |
296 bool GetValue(const char* desc, int64_t* value); | |
297 | |
298 bool PrintValue(const char* desc); | |
299 | |
300 // Push an address onto the JS stack. | |
301 uintptr_t PushAddress(uintptr_t address); | |
302 | |
303 // Pop an address from the JS stack. | |
304 uintptr_t PopAddress(); | |
305 | |
306 // Accessor to the internal simulator stack area. | |
307 uintptr_t StackLimit() const; | |
308 | |
309 void ResetState(); | |
310 | |
311 // Runtime call support. | |
312 static void* RedirectExternalReference(void* external_function, | |
313 ExternalReference::Type type); | |
314 void DoRuntimeCall(Instruction* instr); | |
315 | |
316 // Run the simulator. | |
317 static const Instruction* kEndOfSimAddress; | |
318 void DecodeInstruction(); | |
319 void Run(); | |
320 void RunFrom(Instruction* start); | |
321 | |
322 // Simulation helpers. | |
323 template <typename T> | |
324 void set_pc(T new_pc) { | |
325 ASSERT(sizeof(T) == sizeof(pc_)); | |
326 memcpy(&pc_, &new_pc, sizeof(T)); | |
327 pc_modified_ = true; | |
328 } | |
329 Instruction* pc() { return pc_; } | |
330 | |
331 void increment_pc() { | |
332 if (!pc_modified_) { | |
333 pc_ = pc_->following(); | |
334 } | |
335 | |
336 pc_modified_ = false; | |
337 } | |
338 | |
339 virtual void Decode(Instruction* instr) { | |
340 decoder_->Decode(instr); | |
341 } | |
342 | |
343 void ExecuteInstruction() { | |
344 ASSERT(IsAligned(reinterpret_cast<uintptr_t>(pc_), kInstructionSize)); | |
345 CheckBreakNext(); | |
346 Decode(pc_); | |
347 LogProcessorState(); | |
348 increment_pc(); | |
349 CheckBreakpoints(); | |
350 } | |
351 | |
352 // Declare all Visitor functions. | |
353 #define DECLARE(A) void Visit##A(Instruction* instr); | |
354 VISITOR_LIST(DECLARE) | |
355 #undef DECLARE | |
356 | |
357 // Register accessors. | |
358 | |
359 // Return 'size' bits of the value of an integer register, as the specified | |
360 // type. The value is zero-extended to fill the result. | |
361 // | |
362 // The only supported values of 'size' are kXRegSizeInBits and | |
363 // kWRegSizeInBits. | |
364 template<typename T> | |
365 T reg(unsigned size, unsigned code, | |
366 Reg31Mode r31mode = Reg31IsZeroRegister) const { | |
367 unsigned size_in_bytes = size / 8; | |
368 ASSERT(size_in_bytes <= sizeof(T)); | |
369 ASSERT((size == kXRegSizeInBits) || (size == kWRegSizeInBits)); | |
370 ASSERT(code < kNumberOfRegisters); | |
371 | |
372 if ((code == 31) && (r31mode == Reg31IsZeroRegister)) { | |
373 T result; | |
374 memset(&result, 0, sizeof(result)); | |
375 return result; | |
376 } | |
377 return registers_[code].Get<T>(size_in_bytes); | |
378 } | |
379 | |
380 // Like reg(), but infer the access size from the template type. | |
381 template<typename T> | |
382 T reg(unsigned code, Reg31Mode r31mode = Reg31IsZeroRegister) const { | |
383 return reg<T>(sizeof(T) * 8, code, r31mode); | |
384 } | |
385 | |
386 // Common specialized accessors for the reg() template. | |
387 int32_t wreg(unsigned code, | |
388 Reg31Mode r31mode = Reg31IsZeroRegister) const { | |
389 return reg<int32_t>(code, r31mode); | |
390 } | |
391 | |
392 int64_t xreg(unsigned code, | |
393 Reg31Mode r31mode = Reg31IsZeroRegister) const { | |
394 return reg<int64_t>(code, r31mode); | |
395 } | |
396 | |
397 int64_t reg(unsigned size, unsigned code, | |
398 Reg31Mode r31mode = Reg31IsZeroRegister) const { | |
399 return reg<int64_t>(size, code, r31mode); | |
400 } | |
401 | |
402 // Write 'size' bits of 'value' into an integer register. The value is | |
403 // zero-extended. This behaviour matches AArch64 register writes. | |
404 // | |
405 // The only supported values of 'size' are kXRegSizeInBits and | |
406 // kWRegSizeInBits. | |
407 template<typename T> | |
408 void set_reg(unsigned size, unsigned code, T value, | |
409 Reg31Mode r31mode = Reg31IsZeroRegister) { | |
410 unsigned size_in_bytes = size / 8; | |
411 ASSERT(size_in_bytes <= sizeof(T)); | |
412 ASSERT((size == kXRegSizeInBits) || (size == kWRegSizeInBits)); | |
413 ASSERT(code < kNumberOfRegisters); | |
414 | |
415 if ((code == 31) && (r31mode == Reg31IsZeroRegister)) { | |
416 return; | |
417 } | |
418 return registers_[code].Set(value, size_in_bytes); | |
419 } | |
420 | |
421 // Like set_reg(), but infer the access size from the template type. | |
422 template<typename T> | |
423 void set_reg(unsigned code, T value, | |
424 Reg31Mode r31mode = Reg31IsZeroRegister) { | |
425 set_reg(sizeof(value) * 8, code, value, r31mode); | |
426 } | |
427 | |
428 // Common specialized accessors for the set_reg() template. | |
429 void set_wreg(unsigned code, int32_t value, | |
430 Reg31Mode r31mode = Reg31IsZeroRegister) { | |
431 set_reg(kWRegSizeInBits, code, value, r31mode); | |
432 } | |
433 | |
434 void set_xreg(unsigned code, int64_t value, | |
435 Reg31Mode r31mode = Reg31IsZeroRegister) { | |
436 set_reg(kXRegSizeInBits, code, value, r31mode); | |
437 } | |
438 | |
439 // Commonly-used special cases. | |
440 template<typename T> | |
441 void set_lr(T value) { | |
442 ASSERT(sizeof(T) == kPointerSize); | |
443 set_reg(kLinkRegCode, value); | |
444 } | |
445 | |
446 template<typename T> | |
447 void set_sp(T value) { | |
448 ASSERT(sizeof(T) == kPointerSize); | |
449 set_reg(31, value, Reg31IsStackPointer); | |
450 } | |
451 | |
452 int64_t sp() { return xreg(31, Reg31IsStackPointer); } | |
453 int64_t jssp() { return xreg(kJSSPCode, Reg31IsStackPointer); } | |
454 int64_t fp() { | |
455 return xreg(kFramePointerRegCode, Reg31IsStackPointer); | |
456 } | |
457 Instruction* lr() { return reg<Instruction*>(kLinkRegCode); } | |
458 | |
459 Address get_sp() { return reg<Address>(31, Reg31IsStackPointer); } | |
460 | |
461 // Return 'size' bits of the value of a floating-point register, as the | |
462 // specified type. The value is zero-extended to fill the result. | |
463 // | |
464 // The only supported values of 'size' are kDRegSizeInBits and | |
465 // kSRegSizeInBits. | |
466 template<typename T> | |
467 T fpreg(unsigned size, unsigned code) const { | |
468 unsigned size_in_bytes = size / 8; | |
469 ASSERT(size_in_bytes <= sizeof(T)); | |
470 ASSERT((size == kDRegSizeInBits) || (size == kSRegSizeInBits)); | |
471 ASSERT(code < kNumberOfFPRegisters); | |
472 return fpregisters_[code].Get<T>(size_in_bytes); | |
473 } | |
474 | |
475 // Like fpreg(), but infer the access size from the template type. | |
476 template<typename T> | |
477 T fpreg(unsigned code) const { | |
478 return fpreg<T>(sizeof(T) * 8, code); | |
479 } | |
480 | |
481 // Common specialized accessors for the fpreg() template. | |
482 float sreg(unsigned code) const { | |
483 return fpreg<float>(code); | |
484 } | |
485 | |
486 uint32_t sreg_bits(unsigned code) const { | |
487 return fpreg<uint32_t>(code); | |
488 } | |
489 | |
490 double dreg(unsigned code) const { | |
491 return fpreg<double>(code); | |
492 } | |
493 | |
494 uint64_t dreg_bits(unsigned code) const { | |
495 return fpreg<uint64_t>(code); | |
496 } | |
497 | |
498 double fpreg(unsigned size, unsigned code) const { | |
499 switch (size) { | |
500 case kSRegSizeInBits: return sreg(code); | |
501 case kDRegSizeInBits: return dreg(code); | |
502 default: | |
503 UNREACHABLE(); | |
504 return 0.0; | |
505 } | |
506 } | |
507 | |
508 // Write 'value' into a floating-point register. The value is zero-extended. | |
509 // This behaviour matches AArch64 register writes. | |
510 template<typename T> | |
511 void set_fpreg(unsigned code, T value) { | |
512 ASSERT((sizeof(value) == kDRegSize) || (sizeof(value) == kSRegSize)); | |
513 ASSERT(code < kNumberOfFPRegisters); | |
514 fpregisters_[code].Set(value, sizeof(value)); | |
515 } | |
516 | |
517 // Common specialized accessors for the set_fpreg() template. | |
518 void set_sreg(unsigned code, float value) { | |
519 set_fpreg(code, value); | |
520 } | |
521 | |
522 void set_sreg_bits(unsigned code, uint32_t value) { | |
523 set_fpreg(code, value); | |
524 } | |
525 | |
526 void set_dreg(unsigned code, double value) { | |
527 set_fpreg(code, value); | |
528 } | |
529 | |
530 void set_dreg_bits(unsigned code, uint64_t value) { | |
531 set_fpreg(code, value); | |
532 } | |
533 | |
534 SimSystemRegister& nzcv() { return nzcv_; } | |
535 SimSystemRegister& fpcr() { return fpcr_; } | |
536 | |
537 // Debug helpers | |
538 | |
539 // Simulator breakpoints. | |
540 struct Breakpoint { | |
541 Instruction* location; | |
542 bool enabled; | |
543 }; | |
544 std::vector<Breakpoint> breakpoints_; | |
545 void SetBreakpoint(Instruction* breakpoint); | |
546 void ListBreakpoints(); | |
547 void CheckBreakpoints(); | |
548 | |
549 // Helpers for the 'next' command. | |
550 // When this is set, the Simulator will insert a breakpoint after the next BL | |
551 // instruction it meets. | |
552 bool break_on_next_; | |
553 // Check if the Simulator should insert a break after the current instruction | |
554 // for the 'next' command. | |
555 void CheckBreakNext(); | |
556 | |
557 // Disassemble instruction at the given address. | |
558 void PrintInstructionsAt(Instruction* pc, uint64_t count); | |
559 | |
560 void PrintSystemRegisters(bool print_all = false); | |
561 void PrintRegisters(bool print_all_regs = false); | |
562 void PrintFPRegisters(bool print_all_regs = false); | |
563 void PrintProcessorState(); | |
564 void PrintWrite(uint8_t* address, uint64_t value, unsigned num_bytes); | |
565 void LogSystemRegisters() { | |
566 if (log_parameters_ & LOG_SYS_REGS) PrintSystemRegisters(); | |
567 } | |
568 void LogRegisters() { | |
569 if (log_parameters_ & LOG_REGS) PrintRegisters(); | |
570 } | |
571 void LogFPRegisters() { | |
572 if (log_parameters_ & LOG_FP_REGS) PrintFPRegisters(); | |
573 } | |
574 void LogProcessorState() { | |
575 LogSystemRegisters(); | |
576 LogRegisters(); | |
577 LogFPRegisters(); | |
578 } | |
579 void LogWrite(uint8_t* address, uint64_t value, unsigned num_bytes) { | |
580 if (log_parameters_ & LOG_WRITE) PrintWrite(address, value, num_bytes); | |
581 } | |
582 | |
583 int log_parameters() { return log_parameters_; } | |
584 void set_log_parameters(int new_parameters) { | |
585 log_parameters_ = new_parameters; | |
586 if (!decoder_) { | |
587 if (new_parameters & LOG_DISASM) { | |
588 PrintF("Run --debug-sim to dynamically turn on disassembler\n"); | |
589 } | |
590 return; | |
591 } | |
592 if (new_parameters & LOG_DISASM) { | |
593 decoder_->InsertVisitorBefore(print_disasm_, this); | |
594 } else { | |
595 decoder_->RemoveVisitor(print_disasm_); | |
596 } | |
597 } | |
598 | |
599 static inline const char* WRegNameForCode(unsigned code, | |
600 Reg31Mode mode = Reg31IsZeroRegister); | |
601 static inline const char* XRegNameForCode(unsigned code, | |
602 Reg31Mode mode = Reg31IsZeroRegister); | |
603 static inline const char* SRegNameForCode(unsigned code); | |
604 static inline const char* DRegNameForCode(unsigned code); | |
605 static inline const char* VRegNameForCode(unsigned code); | |
606 static inline int CodeFromName(const char* name); | |
607 | |
608 protected: | |
609 // Simulation helpers ------------------------------------ | |
610 bool ConditionPassed(Condition cond) { | |
611 SimSystemRegister& flags = nzcv(); | |
612 switch (cond) { | |
613 case eq: | |
614 return flags.Z(); | |
615 case ne: | |
616 return !flags.Z(); | |
617 case hs: | |
618 return flags.C(); | |
619 case lo: | |
620 return !flags.C(); | |
621 case mi: | |
622 return flags.N(); | |
623 case pl: | |
624 return !flags.N(); | |
625 case vs: | |
626 return flags.V(); | |
627 case vc: | |
628 return !flags.V(); | |
629 case hi: | |
630 return flags.C() && !flags.Z(); | |
631 case ls: | |
632 return !(flags.C() && !flags.Z()); | |
633 case ge: | |
634 return flags.N() == flags.V(); | |
635 case lt: | |
636 return flags.N() != flags.V(); | |
637 case gt: | |
638 return !flags.Z() && (flags.N() == flags.V()); | |
639 case le: | |
640 return !(!flags.Z() && (flags.N() == flags.V())); | |
641 case nv: // Fall through. | |
642 case al: | |
643 return true; | |
644 default: | |
645 UNREACHABLE(); | |
646 return false; | |
647 } | |
648 } | |
649 | |
650 bool ConditionFailed(Condition cond) { | |
651 return !ConditionPassed(cond); | |
652 } | |
653 | |
654 void AddSubHelper(Instruction* instr, int64_t op2); | |
655 int64_t AddWithCarry(unsigned reg_size, | |
656 bool set_flags, | |
657 int64_t src1, | |
658 int64_t src2, | |
659 int64_t carry_in = 0); | |
660 void LogicalHelper(Instruction* instr, int64_t op2); | |
661 void ConditionalCompareHelper(Instruction* instr, int64_t op2); | |
662 void LoadStoreHelper(Instruction* instr, | |
663 int64_t offset, | |
664 AddrMode addrmode); | |
665 void LoadStorePairHelper(Instruction* instr, AddrMode addrmode); | |
666 uint8_t* LoadStoreAddress(unsigned addr_reg, | |
667 int64_t offset, | |
668 AddrMode addrmode); | |
669 void LoadStoreWriteBack(unsigned addr_reg, | |
670 int64_t offset, | |
671 AddrMode addrmode); | |
672 void CheckMemoryAccess(uint8_t* address, uint8_t* stack); | |
673 | |
674 uint64_t MemoryRead(uint8_t* address, unsigned num_bytes); | |
675 uint8_t MemoryRead8(uint8_t* address); | |
676 uint16_t MemoryRead16(uint8_t* address); | |
677 uint32_t MemoryRead32(uint8_t* address); | |
678 float MemoryReadFP32(uint8_t* address); | |
679 uint64_t MemoryRead64(uint8_t* address); | |
680 double MemoryReadFP64(uint8_t* address); | |
681 | |
682 void MemoryWrite(uint8_t* address, uint64_t value, unsigned num_bytes); | |
683 void MemoryWrite32(uint8_t* address, uint32_t value); | |
684 void MemoryWriteFP32(uint8_t* address, float value); | |
685 void MemoryWrite64(uint8_t* address, uint64_t value); | |
686 void MemoryWriteFP64(uint8_t* address, double value); | |
687 | |
688 int64_t ShiftOperand(unsigned reg_size, | |
689 int64_t value, | |
690 Shift shift_type, | |
691 unsigned amount); | |
692 int64_t Rotate(unsigned reg_width, | |
693 int64_t value, | |
694 Shift shift_type, | |
695 unsigned amount); | |
696 int64_t ExtendValue(unsigned reg_width, | |
697 int64_t value, | |
698 Extend extend_type, | |
699 unsigned left_shift = 0); | |
700 | |
701 uint64_t ReverseBits(uint64_t value, unsigned num_bits); | |
702 uint64_t ReverseBytes(uint64_t value, ReverseByteMode mode); | |
703 | |
704 template <typename T> | |
705 T FPDefaultNaN() const; | |
706 | |
707 void FPCompare(double val0, double val1); | |
708 double FPRoundInt(double value, FPRounding round_mode); | |
709 double FPToDouble(float value); | |
710 float FPToFloat(double value, FPRounding round_mode); | |
711 double FixedToDouble(int64_t src, int fbits, FPRounding round_mode); | |
712 double UFixedToDouble(uint64_t src, int fbits, FPRounding round_mode); | |
713 float FixedToFloat(int64_t src, int fbits, FPRounding round_mode); | |
714 float UFixedToFloat(uint64_t src, int fbits, FPRounding round_mode); | |
715 int32_t FPToInt32(double value, FPRounding rmode); | |
716 int64_t FPToInt64(double value, FPRounding rmode); | |
717 uint32_t FPToUInt32(double value, FPRounding rmode); | |
718 uint64_t FPToUInt64(double value, FPRounding rmode); | |
719 | |
720 template <typename T> | |
721 T FPAdd(T op1, T op2); | |
722 | |
723 template <typename T> | |
724 T FPDiv(T op1, T op2); | |
725 | |
726 template <typename T> | |
727 T FPMax(T a, T b); | |
728 | |
729 template <typename T> | |
730 T FPMaxNM(T a, T b); | |
731 | |
732 template <typename T> | |
733 T FPMin(T a, T b); | |
734 | |
735 template <typename T> | |
736 T FPMinNM(T a, T b); | |
737 | |
738 template <typename T> | |
739 T FPMul(T op1, T op2); | |
740 | |
741 template <typename T> | |
742 T FPMulAdd(T a, T op1, T op2); | |
743 | |
744 template <typename T> | |
745 T FPSqrt(T op); | |
746 | |
747 template <typename T> | |
748 T FPSub(T op1, T op2); | |
749 | |
750 // Standard NaN processing. | |
751 template <typename T> | |
752 T FPProcessNaN(T op); | |
753 | |
754 bool FPProcessNaNs(Instruction* instr); | |
755 | |
756 template <typename T> | |
757 T FPProcessNaNs(T op1, T op2); | |
758 | |
759 template <typename T> | |
760 T FPProcessNaNs3(T op1, T op2, T op3); | |
761 | |
762 void CheckStackAlignment(); | |
763 | |
764 inline void CheckPCSComplianceAndRun(); | |
765 | |
766 #ifdef DEBUG | |
767 // Corruption values should have their least significant byte cleared to | |
768 // allow the code of the register being corrupted to be inserted. | |
769 static const uint64_t kCallerSavedRegisterCorruptionValue = | |
770 0xca11edc0de000000UL; | |
771 // This value is a NaN in both 32-bit and 64-bit FP. | |
772 static const uint64_t kCallerSavedFPRegisterCorruptionValue = | |
773 0x7ff000007f801000UL; | |
774 // This value is a mix of 32/64-bits NaN and "verbose" immediate. | |
775 static const uint64_t kDefaultCPURegisterCorruptionValue = | |
776 0x7ffbad007f8bad00UL; | |
777 | |
778 void CorruptRegisters(CPURegList* list, | |
779 uint64_t value = kDefaultCPURegisterCorruptionValue); | |
780 void CorruptAllCallerSavedCPURegisters(); | |
781 #endif | |
782 | |
783 // Processor state --------------------------------------- | |
784 | |
785 // Output stream. | |
786 FILE* stream_; | |
787 PrintDisassembler* print_disasm_; | |
788 | |
789 // Instrumentation. | |
790 Instrument* instrument_; | |
791 | |
792 // General purpose registers. Register 31 is the stack pointer. | |
793 SimRegister registers_[kNumberOfRegisters]; | |
794 | |
795 // Floating point registers | |
796 SimFPRegister fpregisters_[kNumberOfFPRegisters]; | |
797 | |
798 // Processor state | |
799 // bits[31, 27]: Condition flags N, Z, C, and V. | |
800 // (Negative, Zero, Carry, Overflow) | |
801 SimSystemRegister nzcv_; | |
802 | |
803 // Floating-Point Control Register | |
804 SimSystemRegister fpcr_; | |
805 | |
806 // Only a subset of FPCR features are supported by the simulator. This helper | |
807 // checks that the FPCR settings are supported. | |
808 // | |
809 // This is checked when floating-point instructions are executed, not when | |
810 // FPCR is set. This allows generated code to modify FPCR for external | |
811 // functions, or to save and restore it when entering and leaving generated | |
812 // code. | |
813 void AssertSupportedFPCR() { | |
814 ASSERT(fpcr().FZ() == 0); // No flush-to-zero support. | |
815 ASSERT(fpcr().RMode() == FPTieEven); // Ties-to-even rounding only. | |
816 | |
817 // The simulator does not support half-precision operations so fpcr().AHP() | |
818 // is irrelevant, and is not checked here. | |
819 } | |
820 | |
821 static int CalcNFlag(uint64_t result, unsigned reg_size) { | |
822 return (result >> (reg_size - 1)) & 1; | |
823 } | |
824 | |
825 static int CalcZFlag(uint64_t result) { | |
826 return result == 0; | |
827 } | |
828 | |
829 static const uint32_t kConditionFlagsMask = 0xf0000000; | |
830 | |
831 // Stack | |
832 byte* stack_; | |
833 static const intptr_t stack_protection_size_ = KB; | |
834 intptr_t stack_size_; | |
835 byte* stack_limit_; | |
836 | |
837 Decoder<DispatchingDecoderVisitor>* decoder_; | |
838 Decoder<DispatchingDecoderVisitor>* disassembler_decoder_; | |
839 | |
840 // Indicates if the pc has been modified by the instruction and should not be | |
841 // automatically incremented. | |
842 bool pc_modified_; | |
843 Instruction* pc_; | |
844 | |
845 static const char* xreg_names[]; | |
846 static const char* wreg_names[]; | |
847 static const char* sreg_names[]; | |
848 static const char* dreg_names[]; | |
849 static const char* vreg_names[]; | |
850 | |
851 // Debugger input. | |
852 void set_last_debugger_input(char* input) { | |
853 DeleteArray(last_debugger_input_); | |
854 last_debugger_input_ = input; | |
855 } | |
856 char* last_debugger_input() { return last_debugger_input_; } | |
857 char* last_debugger_input_; | |
858 | |
859 private: | |
860 void Init(FILE* stream); | |
861 | |
862 int log_parameters_; | |
863 Isolate* isolate_; | |
864 }; | |
865 | |
866 | |
867 // When running with the simulator transition into simulated execution at this | |
868 // point. | |
869 #define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \ | |
870 reinterpret_cast<Object*>(Simulator::current(Isolate::Current())->CallJS( \ | |
871 FUNCTION_ADDR(entry), \ | |
872 p0, p1, p2, p3, p4)) | |
873 | |
874 #define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7, p8) \ | |
875 Simulator::current(Isolate::Current())->CallRegExp( \ | |
876 entry, \ | |
877 p0, p1, p2, p3, p4, p5, p6, p7, NULL, p8) | |
878 | |
879 #define TRY_CATCH_FROM_ADDRESS(try_catch_address) \ | |
880 try_catch_address == NULL ? \ | |
881 NULL : *(reinterpret_cast<TryCatch**>(try_catch_address)) | |
882 | |
883 | |
884 // The simulator has its own stack. Thus it has a different stack limit from | |
885 // the C-based native code. | |
886 // See also 'class SimulatorStack' in arm/simulator-arm.h. | |
887 class SimulatorStack : public v8::internal::AllStatic { | |
888 public: | |
889 static uintptr_t JsLimitFromCLimit(v8::internal::Isolate* isolate, | |
890 uintptr_t c_limit) { | |
891 return Simulator::current(isolate)->StackLimit(); | |
892 } | |
893 | |
894 static uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) { | |
895 Simulator* sim = Simulator::current(Isolate::Current()); | |
896 return sim->PushAddress(try_catch_address); | |
897 } | |
898 | |
899 static void UnregisterCTryCatch() { | |
900 Simulator::current(Isolate::Current())->PopAddress(); | |
901 } | |
902 }; | |
903 | |
904 #endif // !defined(USE_SIMULATOR) | |
905 | |
906 } } // namespace v8::internal | |
907 | |
908 #endif // V8_A64_SIMULATOR_A64_H_ | |
OLD | NEW |