OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 | 5 |
6 // Declares a Simulator for ARM instructions if we are not generating a native | 6 // Declares a Simulator for ARM instructions if we are not generating a native |
7 // ARM binary. This Simulator allows us to run and debug ARM code generation on | 7 // ARM binary. This Simulator allows us to run and debug ARM code generation on |
8 // regular desktop machines. | 8 // regular desktop machines. |
9 // V8 calls into generated code by "calling" the CALL_GENERATED_CODE macro, | 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 | 10 // which will start execution in the Simulator or forwards to the real entry |
11 // on a ARM HW platform. | 11 // on a ARM HW platform. |
12 | 12 |
13 #ifndef V8_ARM_SIMULATOR_ARM_H_ | 13 #ifndef V8_ARM_SIMULATOR_ARM_H_ |
14 #define V8_ARM_SIMULATOR_ARM_H_ | 14 #define V8_ARM_SIMULATOR_ARM_H_ |
15 | 15 |
16 #include "src/allocation.h" | 16 #include "src/allocation.h" |
| 17 #include "src/base/lazy-instance.h" |
| 18 #include "src/base/platform/mutex.h" |
17 | 19 |
18 #if !defined(USE_SIMULATOR) | 20 #if !defined(USE_SIMULATOR) |
19 // Running without a simulator on a native arm platform. | 21 // Running without a simulator on a native arm platform. |
20 | 22 |
21 namespace v8 { | 23 namespace v8 { |
22 namespace internal { | 24 namespace internal { |
23 | 25 |
24 // When running without a simulator we call the entry directly. | 26 // When running without a simulator we call the entry directly. |
25 #define CALL_GENERATED_CODE(isolate, entry, p0, p1, p2, p3, p4) \ | 27 #define CALL_GENERATED_CODE(isolate, entry, p0, p1, p2, p3, p4) \ |
26 (entry(p0, p1, p2, p3, p4)) | 28 (entry(p0, p1, p2, p3, p4)) |
(...skipping 268 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
295 // Stop helper functions. | 297 // Stop helper functions. |
296 inline bool isStopInstruction(Instruction* instr); | 298 inline bool isStopInstruction(Instruction* instr); |
297 inline bool isWatchedStop(uint32_t bkpt_code); | 299 inline bool isWatchedStop(uint32_t bkpt_code); |
298 inline bool isEnabledStop(uint32_t bkpt_code); | 300 inline bool isEnabledStop(uint32_t bkpt_code); |
299 inline void EnableStop(uint32_t bkpt_code); | 301 inline void EnableStop(uint32_t bkpt_code); |
300 inline void DisableStop(uint32_t bkpt_code); | 302 inline void DisableStop(uint32_t bkpt_code); |
301 inline void IncreaseStopCounter(uint32_t bkpt_code); | 303 inline void IncreaseStopCounter(uint32_t bkpt_code); |
302 void PrintStopInfo(uint32_t code); | 304 void PrintStopInfo(uint32_t code); |
303 | 305 |
304 // Read and write memory. | 306 // Read and write memory. |
| 307 // The *Ex functions are exclusive access. The writes return the strex status: |
| 308 // 0 if the write succeeds, and 1 if the write fails. |
305 inline uint8_t ReadBU(int32_t addr); | 309 inline uint8_t ReadBU(int32_t addr); |
306 inline int8_t ReadB(int32_t addr); | 310 inline int8_t ReadB(int32_t addr); |
| 311 uint8_t ReadExBU(int32_t addr); |
307 inline void WriteB(int32_t addr, uint8_t value); | 312 inline void WriteB(int32_t addr, uint8_t value); |
308 inline void WriteB(int32_t addr, int8_t value); | 313 inline void WriteB(int32_t addr, int8_t value); |
| 314 int WriteExB(int32_t addr, uint8_t value); |
309 | 315 |
310 inline uint16_t ReadHU(int32_t addr, Instruction* instr); | 316 inline uint16_t ReadHU(int32_t addr, Instruction* instr); |
311 inline int16_t ReadH(int32_t addr, Instruction* instr); | 317 inline int16_t ReadH(int32_t addr, Instruction* instr); |
| 318 uint16_t ReadExHU(int32_t addr, Instruction* instr); |
312 // Note: Overloaded on the sign of the value. | 319 // Note: Overloaded on the sign of the value. |
313 inline void WriteH(int32_t addr, uint16_t value, Instruction* instr); | 320 inline void WriteH(int32_t addr, uint16_t value, Instruction* instr); |
314 inline void WriteH(int32_t addr, int16_t value, Instruction* instr); | 321 inline void WriteH(int32_t addr, int16_t value, Instruction* instr); |
| 322 int WriteExH(int32_t addr, uint16_t value, Instruction* instr); |
315 | 323 |
316 inline int ReadW(int32_t addr, Instruction* instr); | 324 inline int ReadW(int32_t addr, Instruction* instr); |
| 325 int ReadExW(int32_t addr, Instruction* instr); |
317 inline void WriteW(int32_t addr, int value, Instruction* instr); | 326 inline void WriteW(int32_t addr, int value, Instruction* instr); |
| 327 int WriteExW(int32_t addr, int value, Instruction* instr); |
318 | 328 |
319 int32_t* ReadDW(int32_t addr); | 329 int32_t* ReadDW(int32_t addr); |
320 void WriteDW(int32_t addr, int32_t value1, int32_t value2); | 330 void WriteDW(int32_t addr, int32_t value1, int32_t value2); |
321 | 331 |
322 // Executing is handled based on the instruction type. | 332 // Executing is handled based on the instruction type. |
323 // Both type 0 and type 1 rolled into one. | 333 // Both type 0 and type 1 rolled into one. |
324 void DecodeType01(Instruction* instr); | 334 void DecodeType01(Instruction* instr); |
325 void DecodeType2(Instruction* instr); | 335 void DecodeType2(Instruction* instr); |
326 void DecodeType3(Instruction* instr); | 336 void DecodeType3(Instruction* instr); |
327 void DecodeType4(Instruction* instr); | 337 void DecodeType4(Instruction* instr); |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
430 | 440 |
431 // A stop is enabled, meaning the simulator will stop when meeting the | 441 // A stop is enabled, meaning the simulator will stop when meeting the |
432 // instruction, if bit 31 of watched_stops_[code].count is unset. | 442 // instruction, if bit 31 of watched_stops_[code].count is unset. |
433 // The value watched_stops_[code].count & ~(1 << 31) indicates how many times | 443 // The value watched_stops_[code].count & ~(1 << 31) indicates how many times |
434 // the breakpoint was hit or gone through. | 444 // the breakpoint was hit or gone through. |
435 struct StopCountAndDesc { | 445 struct StopCountAndDesc { |
436 uint32_t count; | 446 uint32_t count; |
437 char* desc; | 447 char* desc; |
438 }; | 448 }; |
439 StopCountAndDesc watched_stops_[kNumOfWatchedStops]; | 449 StopCountAndDesc watched_stops_[kNumOfWatchedStops]; |
| 450 |
| 451 // Syncronization primitives. See ARM DDI 0406C.b, A2.9. |
| 452 enum class MonitorAccess { |
| 453 Open, |
| 454 Exclusive, |
| 455 }; |
| 456 |
| 457 enum class TransactionSize { |
| 458 None = 0, |
| 459 Byte = 1, |
| 460 HalfWord = 2, |
| 461 Word = 4, |
| 462 }; |
| 463 |
| 464 // The least-significant bits of the address are ignored. The number of bits |
| 465 // is implementation-defined, between 3 and 11. See ARM DDI 0406C.b, A3.4.3. |
| 466 static const int32_t kExclusiveTaggedAddrMask = ~((1 << 11) - 1); |
| 467 |
| 468 class LocalMonitor { |
| 469 public: |
| 470 LocalMonitor(); |
| 471 |
| 472 // These functions manage the state machine for the local monitor, but do |
| 473 // not actually perform loads and stores. NotifyStoreExcl only returns |
| 474 // true if the exclusive store is allowed; the global monitor will still |
| 475 // have to be checked to see whether the memory should be updated. |
| 476 void NotifyLoad(int32_t addr); |
| 477 void NotifyLoadExcl(int32_t addr, TransactionSize size); |
| 478 void NotifyStore(int32_t addr); |
| 479 bool NotifyStoreExcl(int32_t addr, TransactionSize size); |
| 480 |
| 481 private: |
| 482 void Clear(); |
| 483 |
| 484 MonitorAccess access_state_; |
| 485 int32_t tagged_addr_; |
| 486 TransactionSize size_; |
| 487 }; |
| 488 |
| 489 class GlobalMonitor { |
| 490 public: |
| 491 GlobalMonitor(); |
| 492 |
| 493 class Processor { |
| 494 public: |
| 495 Processor(); |
| 496 |
| 497 private: |
| 498 friend class GlobalMonitor; |
| 499 // These functions manage the state machine for the global monitor, but do |
| 500 // not actually perform loads and stores. |
| 501 void Clear_Locked(); |
| 502 void NotifyLoadExcl_Locked(int32_t addr); |
| 503 void NotifyStore_Locked(int32_t addr, bool is_requesting_processor); |
| 504 bool NotifyStoreExcl_Locked(int32_t addr, bool is_requesting_processor); |
| 505 |
| 506 MonitorAccess access_state_; |
| 507 int32_t tagged_addr_; |
| 508 Processor* next_; |
| 509 Processor* prev_; |
| 510 // A strex can fail due to background cache evictions. Rather than |
| 511 // simulating this, we'll just occasionally introduce cases where an |
| 512 // exclusive store fails. This will happen once after every |
| 513 // kMaxFailureCounter exclusive stores. |
| 514 static const int kMaxFailureCounter = 5; |
| 515 int failure_counter_; |
| 516 }; |
| 517 |
| 518 // Exposed so it can be accessed by Simulator::{Read,Write}Ex*. |
| 519 base::Mutex mutex; |
| 520 |
| 521 void NotifyLoadExcl_Locked(int32_t addr, Processor* processor); |
| 522 void NotifyStore_Locked(int32_t addr, Processor* processor); |
| 523 bool NotifyStoreExcl_Locked(int32_t addr, Processor* processor); |
| 524 |
| 525 // Called when the simulator is destroyed. |
| 526 void RemoveProcessor(Processor* processor); |
| 527 |
| 528 private: |
| 529 bool IsProcessorInLinkedList_Locked(Processor* processor) const; |
| 530 void PrependProcessor_Locked(Processor* processor); |
| 531 |
| 532 Processor* head_; |
| 533 }; |
| 534 |
| 535 LocalMonitor local_monitor_; |
| 536 GlobalMonitor::Processor global_monitor_processor_; |
| 537 static base::LazyInstance<GlobalMonitor>::type global_monitor_; |
440 }; | 538 }; |
441 | 539 |
442 | 540 |
443 // When running with the simulator transition into simulated execution at this | 541 // When running with the simulator transition into simulated execution at this |
444 // point. | 542 // point. |
445 #define CALL_GENERATED_CODE(isolate, entry, p0, p1, p2, p3, p4) \ | 543 #define CALL_GENERATED_CODE(isolate, entry, p0, p1, p2, p3, p4) \ |
446 reinterpret_cast<Object*>(Simulator::current(isolate)->Call( \ | 544 reinterpret_cast<Object*>(Simulator::current(isolate)->Call( \ |
447 FUNCTION_ADDR(entry), 5, p0, p1, p2, p3, p4)) | 545 FUNCTION_ADDR(entry), 5, p0, p1, p2, p3, p4)) |
448 | 546 |
449 #define CALL_GENERATED_FP_INT(isolate, entry, p0, p1) \ | 547 #define CALL_GENERATED_FP_INT(isolate, entry, p0, p1) \ |
(...skipping 25 matching lines...) Expand all Loading... |
475 static inline void UnregisterCTryCatch(v8::internal::Isolate* isolate) { | 573 static inline void UnregisterCTryCatch(v8::internal::Isolate* isolate) { |
476 Simulator::current(isolate)->PopAddress(); | 574 Simulator::current(isolate)->PopAddress(); |
477 } | 575 } |
478 }; | 576 }; |
479 | 577 |
480 } // namespace internal | 578 } // namespace internal |
481 } // namespace v8 | 579 } // namespace v8 |
482 | 580 |
483 #endif // !defined(USE_SIMULATOR) | 581 #endif // !defined(USE_SIMULATOR) |
484 #endif // V8_ARM_SIMULATOR_ARM_H_ | 582 #endif // V8_ARM_SIMULATOR_ARM_H_ |
OLD | NEW |