Index: src/arm/simulator-arm.h |
diff --git a/src/arm/simulator-arm.h b/src/arm/simulator-arm.h |
index 48c2d0f44abb0a32580d36c49930d045ea9cc84b..39d9b7f65c186f16bdacaf49605635fb5c06cb3a 100644 |
--- a/src/arm/simulator-arm.h |
+++ b/src/arm/simulator-arm.h |
@@ -14,6 +14,8 @@ |
#define V8_ARM_SIMULATOR_ARM_H_ |
#include "src/allocation.h" |
+#include "src/base/lazy-instance.h" |
+#include "src/base/platform/mutex.h" |
#if !defined(USE_SIMULATOR) |
// Running without a simulator on a native arm platform. |
@@ -302,19 +304,27 @@ class Simulator { |
void PrintStopInfo(uint32_t code); |
// Read and write memory. |
+ // The *Ex functions are exclusive access. The writes return the strex status: |
+ // 0 if the write succeeds, and 1 if the write fails. |
inline uint8_t ReadBU(int32_t addr); |
inline int8_t ReadB(int32_t addr); |
+ uint8_t ReadExBU(int32_t addr); |
inline void WriteB(int32_t addr, uint8_t value); |
inline void WriteB(int32_t addr, int8_t value); |
+ int WriteExB(int32_t addr, uint8_t value); |
inline uint16_t ReadHU(int32_t addr, Instruction* instr); |
inline int16_t ReadH(int32_t addr, Instruction* instr); |
+ uint16_t ReadExHU(int32_t addr, Instruction* instr); |
// Note: Overloaded on the sign of the value. |
inline void WriteH(int32_t addr, uint16_t value, Instruction* instr); |
inline void WriteH(int32_t addr, int16_t value, Instruction* instr); |
+ int WriteExH(int32_t addr, uint16_t value, Instruction* instr); |
inline int ReadW(int32_t addr, Instruction* instr); |
+ int ReadExW(int32_t addr, Instruction* instr); |
inline void WriteW(int32_t addr, int value, Instruction* instr); |
+ int WriteExW(int32_t addr, int value, Instruction* instr); |
int32_t* ReadDW(int32_t addr); |
void WriteDW(int32_t addr, int32_t value1, int32_t value2); |
@@ -437,6 +447,94 @@ class Simulator { |
char* desc; |
}; |
StopCountAndDesc watched_stops_[kNumOfWatchedStops]; |
+ |
+ // Syncronization primitives. See ARM DDI 0406C.b, A2.9. |
+ enum class MonitorAccess { |
+ Open, |
+ Exclusive, |
+ }; |
+ |
+ enum class TransactionSize { |
+ None = 0, |
+ Byte = 1, |
+ HalfWord = 2, |
+ Word = 4, |
+ }; |
+ |
+ // The least-significant bits of the address are ignored. The number of bits |
+ // is implementation-defined, between 3 and 11. See ARM DDI 0406C.b, A3.4.3. |
+ static const int32_t kExclusiveTaggedAddrMask = ~((1 << 11) - 1); |
+ |
+ class LocalMonitor { |
+ public: |
+ LocalMonitor(); |
+ |
+ // These functions manage the state machine for the local monitor, but do |
+ // not actually perform loads and stores. NotifyStoreExcl only returns |
+ // true if the exclusive store is allowed; the global monitor will still |
+ // have to be checked to see whether the memory should be updated. |
+ void NotifyLoad(int32_t addr); |
+ void NotifyLoadExcl(int32_t addr, TransactionSize size); |
+ void NotifyStore(int32_t addr); |
+ bool NotifyStoreExcl(int32_t addr, TransactionSize size); |
+ |
+ private: |
+ void Clear(); |
+ |
+ MonitorAccess access_state_; |
+ int32_t tagged_addr_; |
+ TransactionSize size_; |
+ }; |
+ |
+ class GlobalMonitor { |
+ public: |
+ GlobalMonitor(); |
+ |
+ class Processor { |
+ public: |
+ Processor(); |
+ |
+ private: |
+ friend class GlobalMonitor; |
+ // These functions manage the state machine for the global monitor, but do |
+ // not actually perform loads and stores. |
+ void Clear_Locked(); |
+ void NotifyLoadExcl_Locked(int32_t addr); |
+ void NotifyStore_Locked(int32_t addr, bool is_requesting_processor); |
+ bool NotifyStoreExcl_Locked(int32_t addr, bool is_requesting_processor); |
+ |
+ MonitorAccess access_state_; |
+ int32_t tagged_addr_; |
+ Processor* next_; |
+ Processor* prev_; |
+ // A strex can fail due to background cache evictions. Rather than |
+ // simulating this, we'll just occasionally introduce cases where an |
+ // exclusive store fails. This will happen once after every |
+ // kMaxFailureCounter exclusive stores. |
+ static const int kMaxFailureCounter = 5; |
+ int failure_counter_; |
+ }; |
+ |
+ // Exposed so it can be accessed by Simulator::{Read,Write}Ex*. |
+ base::Mutex mutex; |
+ |
+ void NotifyLoadExcl_Locked(int32_t addr, Processor* processor); |
+ void NotifyStore_Locked(int32_t addr, Processor* processor); |
+ bool NotifyStoreExcl_Locked(int32_t addr, Processor* processor); |
+ |
+ // Called when the simulator is destroyed. |
+ void RemoveProcessor(Processor* processor); |
+ |
+ private: |
+ bool IsProcessorInLinkedList_Locked(Processor* processor) const; |
+ void PrependProcessor_Locked(Processor* processor); |
+ |
+ Processor* head_; |
+ }; |
+ |
+ LocalMonitor local_monitor_; |
+ GlobalMonitor::Processor global_monitor_processor_; |
+ static base::LazyInstance<GlobalMonitor>::type global_monitor_; |
}; |