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 inline bool isWatchedStop(uint32_t bkpt_code); | 297 inline bool isWatchedStop(uint32_t bkpt_code); |
296 inline bool isEnabledStop(uint32_t bkpt_code); | 298 inline bool isEnabledStop(uint32_t bkpt_code); |
297 inline void EnableStop(uint32_t bkpt_code); | 299 inline void EnableStop(uint32_t bkpt_code); |
298 inline void DisableStop(uint32_t bkpt_code); | 300 inline void DisableStop(uint32_t bkpt_code); |
299 inline void IncreaseStopCounter(uint32_t bkpt_code); | 301 inline void IncreaseStopCounter(uint32_t bkpt_code); |
300 void PrintStopInfo(uint32_t code); | 302 void PrintStopInfo(uint32_t code); |
301 | 303 |
302 // Read and write memory. | 304 // Read and write memory. |
303 inline uint8_t ReadBU(int32_t addr); | 305 inline uint8_t ReadBU(int32_t addr); |
304 inline int8_t ReadB(int32_t addr); | 306 inline int8_t ReadB(int32_t addr); |
305 inline void WriteB(int32_t addr, uint8_t value); | 307 inline void WriteB_Internal(int32_t addr, uint8_t value); |
306 inline void WriteB(int32_t addr, int8_t value); | 308 inline void WriteB_Internal(int32_t addr, int8_t value); |
307 | 309 |
308 inline uint16_t ReadHU(int32_t addr, Instruction* instr); | 310 inline uint16_t ReadHU(int32_t addr, Instruction* instr); |
309 inline int16_t ReadH(int32_t addr, Instruction* instr); | 311 inline int16_t ReadH(int32_t addr, Instruction* instr); |
310 // Note: Overloaded on the sign of the value. | 312 // Note: Overloaded on the sign of the value. |
311 inline void WriteH(int32_t addr, uint16_t value, Instruction* instr); | 313 inline void WriteH_Internal(int32_t addr, uint16_t value, Instruction* instr); |
312 inline void WriteH(int32_t addr, int16_t value, Instruction* instr); | 314 inline void WriteH_Internal(int32_t addr, int16_t value, Instruction* instr); |
313 | 315 |
314 inline int ReadW(int32_t addr, Instruction* instr); | 316 inline int ReadW(int32_t addr, Instruction* instr); |
315 inline void WriteW(int32_t addr, int value, Instruction* instr); | 317 inline void WriteW_Internal(int32_t addr, int value, Instruction* instr); |
316 | 318 |
317 int32_t* ReadDW(int32_t addr); | 319 int32_t* ReadDW(int32_t addr); |
318 void WriteDW(int32_t addr, int32_t value1, int32_t value2); | 320 void WriteDW(int32_t addr, int32_t value1, int32_t value2); |
319 | 321 |
320 // Executing is handled based on the instruction type. | 322 // Executing is handled based on the instruction type. |
321 // Both type 0 and type 1 rolled into one. | 323 // Both type 0 and type 1 rolled into one. |
322 void DecodeType01(Instruction* instr); | 324 void DecodeType01(Instruction* instr); |
323 void DecodeType2(Instruction* instr); | 325 void DecodeType2(Instruction* instr); |
324 void DecodeType3(Instruction* instr); | 326 void DecodeType3(Instruction* instr); |
325 void DecodeType4(Instruction* instr); | 327 void DecodeType4(Instruction* instr); |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
420 | 422 |
421 // A stop is enabled, meaning the simulator will stop when meeting the | 423 // A stop is enabled, meaning the simulator will stop when meeting the |
422 // instruction, if bit 31 of watched_stops_[code].count is unset. | 424 // instruction, if bit 31 of watched_stops_[code].count is unset. |
423 // The value watched_stops_[code].count & ~(1 << 31) indicates how many times | 425 // The value watched_stops_[code].count & ~(1 << 31) indicates how many times |
424 // the breakpoint was hit or gone through. | 426 // the breakpoint was hit or gone through. |
425 struct StopCountAndDesc { | 427 struct StopCountAndDesc { |
426 uint32_t count; | 428 uint32_t count; |
427 char* desc; | 429 char* desc; |
428 }; | 430 }; |
429 StopCountAndDesc watched_stops_[kNumOfWatchedStops]; | 431 StopCountAndDesc watched_stops_[kNumOfWatchedStops]; |
432 | |
433 // Syncronization primitives. See ARM DDI 0406C.b, A2.9. | |
434 enum class MonitorAccess { | |
435 Open, | |
436 Exclusive, | |
437 }; | |
438 | |
439 enum class TransactionSize { | |
440 None = 0, | |
441 Byte = 1, | |
442 HalfWord = 2, | |
443 Word = 4, | |
444 }; | |
445 | |
446 // The least-significant bits of the address are ignored. The number of bits | |
447 // is implementation-defined, between 3 and 11. See ARM DDI 0406C.b, A3.4.3. | |
448 static const int32_t kTaggedAddrMask = ~7; | |
jbramley
2016/07/20 16:09:24
Picking (2^)11 would probably be more demanding on
| |
449 | |
450 // Writes can affect the local and global monitors. | |
451 void WriteB(int32_t addr, uint8_t value); | |
452 void WriteB(int32_t addr, int8_t value); | |
jbramley
2016/07/20 16:09:24
There's no practical difference between storing si
binji
2016/07/29 21:46:30
I agree, and I started to make this change, but it
| |
453 void WriteH(int32_t addr, uint16_t value, Instruction* instr); | |
454 void WriteH(int32_t addr, int16_t value, Instruction* instr); | |
455 void WriteW(int32_t addr, int value, Instruction* instr); | |
jbramley
2016/07/20 16:09:24
I suggest using (u)int32_t explicitly, for consist
binji
2016/07/29 21:46:30
Yes, but I was trying to have consistency with the
| |
456 | |
457 // Read and write exclusive. The writes return the strex status: 0 if the | |
458 // write succeeds, and 1 if the write fails. | |
459 uint8_t ReadExBU(int32_t addr); | |
460 uint16_t ReadExHU(int32_t addr, Instruction* instr); | |
461 int ReadExW(int32_t addr, Instruction* instr); | |
462 int WriteExB(int32_t addr, uint8_t value); | |
463 int WriteExH(int32_t addr, uint16_t value, Instruction* instr); | |
464 int WriteExW(int32_t addr, int value, Instruction* instr); | |
465 | |
466 class LocalMonitor { | |
467 public: | |
468 LocalMonitor(); | |
469 | |
470 // These functions manage the state machine for the local monitor, but do | |
471 // not actually perform loads and stores. | |
472 // CheckStoreExcl only returns true if the exclusive store is allowed; the | |
473 // global monitor will still have to be checked to see whether the memory | |
474 // should be updated. | |
475 void LoadExcl(int32_t addr, TransactionSize size); | |
jbramley
2016/07/20 16:09:24
How about "NotifyLoadExcl" and so on? Then it's cl
binji
2016/07/29 21:46:30
Done.
| |
476 void Store(int32_t addr, TransactionSize size); | |
477 bool CheckStoreExcl(int32_t addr, TransactionSize size); | |
478 | |
479 private: | |
480 MonitorAccess access_state_; | |
481 int32_t tagged_addr_; | |
482 TransactionSize size_; | |
483 }; | |
484 | |
485 class GlobalMonitor { | |
486 public: | |
487 GlobalMonitor(); | |
488 | |
489 class Node { | |
jbramley
2016/07/20 16:09:24
Perhaps "Processor" or something similar would be
binji
2016/07/29 21:46:30
Done.
| |
490 public: | |
491 Node(); | |
492 | |
493 private: | |
494 friend class GlobalMonitor; | |
495 // These functions manage the state machine for the global monitor, but do | |
496 // not actually perform loads and stores. | |
497 void LoadExcl_Locked(int32_t addr); | |
498 void Store_Locked(int32_t addr, bool is_requesting_processor); | |
499 bool CheckStoreExcl_Locked(int32_t addr, bool is_requesting_processor); | |
500 | |
501 MonitorAccess access_state_; | |
502 int32_t tagged_addr_; | |
503 Node* next_; | |
504 Node* prev_; | |
505 }; | |
506 | |
507 // Exposed so it can be accessed by Simulator::{Read,Write}Ex*. | |
508 base::Mutex mutex; | |
509 | |
510 void LoadExcl_Locked(int32_t addr, Node* node); | |
511 void Store_Locked(int32_t addr, Node* node); | |
512 bool CheckStoreExcl_Locked(int32_t addr, Node* node); | |
513 | |
514 // Called when the simulator is destroyed. | |
515 void RemoveNode(Node* node); | |
516 | |
517 private: | |
518 bool IsNodeInLinkedList_Locked(Node* node) const; | |
519 void PrependNode_Locked(Node* node); | |
520 | |
521 Node* head_; | |
522 }; | |
523 | |
524 LocalMonitor local_monitor_; | |
525 GlobalMonitor::Node global_monitor_node_; | |
526 static base::LazyInstance<GlobalMonitor>::type global_monitor_; | |
430 }; | 527 }; |
431 | 528 |
432 | 529 |
433 // When running with the simulator transition into simulated execution at this | 530 // When running with the simulator transition into simulated execution at this |
434 // point. | 531 // point. |
435 #define CALL_GENERATED_CODE(isolate, entry, p0, p1, p2, p3, p4) \ | 532 #define CALL_GENERATED_CODE(isolate, entry, p0, p1, p2, p3, p4) \ |
436 reinterpret_cast<Object*>(Simulator::current(isolate)->Call( \ | 533 reinterpret_cast<Object*>(Simulator::current(isolate)->Call( \ |
437 FUNCTION_ADDR(entry), 5, p0, p1, p2, p3, p4)) | 534 FUNCTION_ADDR(entry), 5, p0, p1, p2, p3, p4)) |
438 | 535 |
439 #define CALL_GENERATED_FP_INT(isolate, entry, p0, p1) \ | 536 #define CALL_GENERATED_FP_INT(isolate, entry, p0, p1) \ |
(...skipping 25 matching lines...) Expand all Loading... | |
465 static inline void UnregisterCTryCatch(v8::internal::Isolate* isolate) { | 562 static inline void UnregisterCTryCatch(v8::internal::Isolate* isolate) { |
466 Simulator::current(isolate)->PopAddress(); | 563 Simulator::current(isolate)->PopAddress(); |
467 } | 564 } |
468 }; | 565 }; |
469 | 566 |
470 } // namespace internal | 567 } // namespace internal |
471 } // namespace v8 | 568 } // namespace v8 |
472 | 569 |
473 #endif // !defined(USE_SIMULATOR) | 570 #endif // !defined(USE_SIMULATOR) |
474 #endif // V8_ARM_SIMULATOR_ARM_H_ | 571 #endif // V8_ARM_SIMULATOR_ARM_H_ |
OLD | NEW |