diff options
Diffstat (limited to 'deps/v8/src/mips/simulator-mips.cc')
-rw-r--r-- | deps/v8/src/mips/simulator-mips.cc | 309 |
1 files changed, 265 insertions, 44 deletions
diff --git a/deps/v8/src/mips/simulator-mips.cc b/deps/v8/src/mips/simulator-mips.cc index b759176db3..f4d8f354d8 100644 --- a/deps/v8/src/mips/simulator-mips.cc +++ b/deps/v8/src/mips/simulator-mips.cc @@ -2,30 +2,31 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "src/mips/simulator-mips.h" + +// Only build the simulator if not compiling for real MIPS hardware. +#if defined(USE_SIMULATOR) + #include <limits.h> #include <stdarg.h> #include <stdlib.h> #include <cmath> -#if V8_TARGET_ARCH_MIPS - #include "src/assembler-inl.h" #include "src/base/bits.h" -#include "src/codegen.h" +#include "src/base/lazy-instance.h" #include "src/disasm.h" #include "src/macro-assembler.h" #include "src/mips/constants-mips.h" -#include "src/mips/simulator-mips.h" #include "src/ostreams.h" #include "src/runtime/runtime-utils.h" - -// Only build the simulator if not compiling for real MIPS hardware. -#if defined(USE_SIMULATOR) - namespace v8 { namespace internal { +DEFINE_LAZY_LEAKY_OBJECT_GETTER(Simulator::GlobalMonitor, + Simulator::GlobalMonitor::Get); + // Utils functions. bool HaveSameSign(int32_t a, int32_t b) { return ((a ^ b) >= 0); @@ -475,7 +476,7 @@ void MipsDebugger::Debug() { int32_t value; StdoutStream os; if (GetValue(arg1, &value)) { - Object* obj = reinterpret_cast<Object*>(value); + Object obj(value); os << arg1 << ": \n"; #ifdef DEBUG obj->Print(os); @@ -532,14 +533,12 @@ void MipsDebugger::Debug() { while (cur < end) { PrintF(" 0x%08" PRIxPTR ": 0x%08x %10d", reinterpret_cast<intptr_t>(cur), *cur, *cur); - HeapObject* obj = reinterpret_cast<HeapObject*>(*cur); - int value = *cur; + Object obj(*cur); Heap* current_heap = sim_->isolate_->heap(); - if (((value & 1) == 0) || - current_heap->ContainsSlow(obj->address())) { + if (obj.IsSmi() || current_heap->Contains(HeapObject::cast(obj))) { PrintF(" ("); - if ((value & 1) == 0) { - PrintF("smi %d", value / 2); + if (obj.IsSmi()) { + PrintF("smi %d", Smi::ToInt(obj)); } else { obj->ShortPrint(); } @@ -916,9 +915,10 @@ Simulator::Simulator(Isolate* isolate) : isolate_(isolate) { last_debugger_input_ = nullptr; } - -Simulator::~Simulator() { free(stack_); } - +Simulator::~Simulator() { + GlobalMonitor::Get()->RemoveLinkedAddress(&global_monitor_thread_); + free(stack_); +} // Get the active Simulator for the current thread. Simulator* Simulator::current(Isolate* isolate) { @@ -1967,6 +1967,7 @@ int Simulator::ReadW(int32_t addr, Instruction* instr, TraceType t) { dbg.Debug(); } if ((addr & kPointerAlignmentMask) == 0 || IsMipsArchVariant(kMips32r6)) { + local_monitor_.NotifyLoad(); intptr_t* ptr = reinterpret_cast<intptr_t*>(addr); switch (t) { case WORD: @@ -1997,6 +1998,9 @@ void Simulator::WriteW(int32_t addr, int value, Instruction* instr) { dbg.Debug(); } if ((addr & kPointerAlignmentMask) == 0 || IsMipsArchVariant(kMips32r6)) { + local_monitor_.NotifyStore(); + base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex); + GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_); intptr_t* ptr = reinterpret_cast<intptr_t*>(addr); TraceMemWr(addr, value, WORD); *ptr = value; @@ -2009,8 +2013,40 @@ void Simulator::WriteW(int32_t addr, int value, Instruction* instr) { dbg.Debug(); } +void Simulator::WriteConditionalW(int32_t addr, int32_t value, + Instruction* instr, int32_t rt_reg) { + if (addr >= 0 && addr < 0x400) { + // This has to be a nullptr-dereference, drop into debugger. + PrintF("Memory write to bad address: 0x%08x, pc=0x%08" PRIxPTR "\n", addr, + reinterpret_cast<intptr_t>(instr)); + MipsDebugger dbg(this); + dbg.Debug(); + } + if ((addr & kPointerAlignmentMask) == 0 || IsMipsArchVariant(kMips32r6)) { + base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex); + if (local_monitor_.NotifyStoreConditional(addr, TransactionSize::Word) && + GlobalMonitor::Get()->NotifyStoreConditional_Locked( + addr, &global_monitor_thread_)) { + local_monitor_.NotifyStore(); + GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_); + TraceMemWr(addr, value, WORD); + int* ptr = reinterpret_cast<int*>(addr); + *ptr = value; + set_register(rt_reg, 1); + } else { + set_register(rt_reg, 0); + } + return; + } + PrintF("Unaligned write at 0x%08x, pc=0x%08" V8PRIxPTR "\n", addr, + reinterpret_cast<intptr_t>(instr)); + MipsDebugger dbg(this); + dbg.Debug(); +} + double Simulator::ReadD(int32_t addr, Instruction* instr) { if ((addr & kDoubleAlignmentMask) == 0 || IsMipsArchVariant(kMips32r6)) { + local_monitor_.NotifyLoad(); double* ptr = reinterpret_cast<double*>(addr); return *ptr; } @@ -2024,6 +2060,9 @@ double Simulator::ReadD(int32_t addr, Instruction* instr) { void Simulator::WriteD(int32_t addr, double value, Instruction* instr) { if ((addr & kDoubleAlignmentMask) == 0 || IsMipsArchVariant(kMips32r6)) { + local_monitor_.NotifyStore(); + base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex); + GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_); double* ptr = reinterpret_cast<double*>(addr); *ptr = value; return; @@ -2037,6 +2076,7 @@ void Simulator::WriteD(int32_t addr, double value, Instruction* instr) { uint16_t Simulator::ReadHU(int32_t addr, Instruction* instr) { if ((addr & 1) == 0 || IsMipsArchVariant(kMips32r6)) { + local_monitor_.NotifyLoad(); uint16_t* ptr = reinterpret_cast<uint16_t*>(addr); TraceMemRd(addr, static_cast<int32_t>(*ptr)); return *ptr; @@ -2051,6 +2091,7 @@ uint16_t Simulator::ReadHU(int32_t addr, Instruction* instr) { int16_t Simulator::ReadH(int32_t addr, Instruction* instr) { if ((addr & 1) == 0 || IsMipsArchVariant(kMips32r6)) { + local_monitor_.NotifyLoad(); int16_t* ptr = reinterpret_cast<int16_t*>(addr); TraceMemRd(addr, static_cast<int32_t>(*ptr)); return *ptr; @@ -2065,6 +2106,9 @@ int16_t Simulator::ReadH(int32_t addr, Instruction* instr) { void Simulator::WriteH(int32_t addr, uint16_t value, Instruction* instr) { if ((addr & 1) == 0 || IsMipsArchVariant(kMips32r6)) { + local_monitor_.NotifyStore(); + base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex); + GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_); uint16_t* ptr = reinterpret_cast<uint16_t*>(addr); TraceMemWr(addr, value, HALF); *ptr = value; @@ -2079,6 +2123,9 @@ void Simulator::WriteH(int32_t addr, uint16_t value, Instruction* instr) { void Simulator::WriteH(int32_t addr, int16_t value, Instruction* instr) { if ((addr & 1) == 0 || IsMipsArchVariant(kMips32r6)) { + local_monitor_.NotifyStore(); + base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex); + GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_); int16_t* ptr = reinterpret_cast<int16_t*>(addr); TraceMemWr(addr, value, HALF); *ptr = value; @@ -2092,6 +2139,7 @@ void Simulator::WriteH(int32_t addr, int16_t value, Instruction* instr) { uint32_t Simulator::ReadBU(int32_t addr) { + local_monitor_.NotifyLoad(); uint8_t* ptr = reinterpret_cast<uint8_t*>(addr); TraceMemRd(addr, static_cast<int32_t>(*ptr)); return *ptr & 0xFF; @@ -2099,6 +2147,7 @@ uint32_t Simulator::ReadBU(int32_t addr) { int32_t Simulator::ReadB(int32_t addr) { + local_monitor_.NotifyLoad(); int8_t* ptr = reinterpret_cast<int8_t*>(addr); TraceMemRd(addr, static_cast<int32_t>(*ptr)); return *ptr; @@ -2106,6 +2155,9 @@ int32_t Simulator::ReadB(int32_t addr) { void Simulator::WriteB(int32_t addr, uint8_t value) { + local_monitor_.NotifyStore(); + base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex); + GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_); uint8_t* ptr = reinterpret_cast<uint8_t*>(addr); TraceMemWr(addr, value, BYTE); *ptr = value; @@ -2113,6 +2165,9 @@ void Simulator::WriteB(int32_t addr, uint8_t value) { void Simulator::WriteB(int32_t addr, int8_t value) { + local_monitor_.NotifyStore(); + base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex); + GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_); int8_t* ptr = reinterpret_cast<int8_t*>(addr); TraceMemWr(addr, value, BYTE); *ptr = value; @@ -2122,6 +2177,7 @@ template <typename T> T Simulator::ReadMem(int32_t addr, Instruction* instr) { int alignment_mask = (1 << sizeof(T)) - 1; if ((addr & alignment_mask) == 0 || IsMipsArchVariant(kMips32r6)) { + local_monitor_.NotifyLoad(); T* ptr = reinterpret_cast<T*>(addr); TraceMemRd(addr, *ptr); return *ptr; @@ -2134,6 +2190,9 @@ T Simulator::ReadMem(int32_t addr, Instruction* instr) { template <typename T> void Simulator::WriteMem(int32_t addr, T value, Instruction* instr) { + local_monitor_.NotifyStore(); + base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex); + GlobalMonitor::Get()->NotifyStore_Locked(&global_monitor_thread_); int alignment_mask = (1 << sizeof(T)) - 1; if ((addr & alignment_mask) == 0 || IsMipsArchVariant(kMips32r6)) { T* ptr = reinterpret_cast<T*>(addr); @@ -4240,21 +4299,6 @@ void Simulator::DecodeTypeRegisterSPECIAL3() { SetResult(rd_reg(), alu_out); break; } - case LL_R6: { - // LLWP/SCWP sequence cannot be simulated properly - DCHECK(IsMipsArchVariant(kMips32r6)); - set_register(rd_reg(), ReadW(rs() + 4, instr_.instr())); - set_register(rt(), ReadW(rs(), instr_.instr())); - break; - } - case SC_R6: { - // LLWP/SCWP sequence cannot be simulated properly - DCHECK(IsMipsArchVariant(kMips32r6)); - WriteW(rs() + 4, rd_reg(), instr_.instr()); - WriteW(rs(), rt(), instr_.instr()); - set_register(rt(), 1); - break; - } default: UNREACHABLE(); } @@ -6742,16 +6786,19 @@ void Simulator::DecodeTypeImmediate() { break; } case LL: { - // LL/SC sequence cannot be simulated properly DCHECK(!IsMipsArchVariant(kMips32r6)); - set_register(rt_reg, ReadW(rs + se_imm16, instr_.instr())); + base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex); + addr = rs + se_imm16; + set_register(rt_reg, ReadW(addr, instr_.instr())); + local_monitor_.NotifyLoadLinked(addr, TransactionSize::Word); + GlobalMonitor::Get()->NotifyLoadLinked_Locked(addr, + &global_monitor_thread_); break; } case SC: { - // LL/SC sequence cannot be simulated properly DCHECK(!IsMipsArchVariant(kMips32r6)); - WriteW(rs + se_imm16, rt, instr_.instr()); - set_register(rt_reg, 1); + addr = rs + se_imm16; + WriteConditionalW(addr, rt, instr_.instr(), rt_reg); break; } case LWC1: @@ -6821,20 +6868,25 @@ void Simulator::DecodeTypeImmediate() { case SPECIAL3: { switch (instr_.FunctionFieldRaw()) { case LL_R6: { - // LL/SC sequence cannot be simulated properly DCHECK(IsMipsArchVariant(kMips32r6)); + base::MutexGuard lock_guard(&GlobalMonitor::Get()->mutex); int32_t base = get_register(instr_.BaseValue()); int32_t offset9 = instr_.Imm9Value(); + addr = base + offset9; + DCHECK_EQ(addr & kPointerAlignmentMask, 0); set_register(rt_reg, ReadW(base + offset9, instr_.instr())); + local_monitor_.NotifyLoadLinked(addr, TransactionSize::Word); + GlobalMonitor::Get()->NotifyLoadLinked_Locked( + addr, &global_monitor_thread_); break; } case SC_R6: { - // LL/SC sequence cannot be simulated properly DCHECK(IsMipsArchVariant(kMips32r6)); int32_t base = get_register(instr_.BaseValue()); int32_t offset9 = instr_.Imm9Value(); - WriteW(base + offset9, rt, instr_.instr()); - set_register(rt_reg, 1); + addr = base + offset9; + DCHECK_EQ(addr & kPointerAlignmentMask, 0); + WriteConditionalW(addr, rt, instr_.instr(), rt_reg); break; } default: @@ -7124,6 +7176,177 @@ uintptr_t Simulator::PopAddress() { return address; } +Simulator::LocalMonitor::LocalMonitor() + : access_state_(MonitorAccess::Open), + tagged_addr_(0), + size_(TransactionSize::None) {} + +void Simulator::LocalMonitor::Clear() { + access_state_ = MonitorAccess::Open; + tagged_addr_ = 0; + size_ = TransactionSize::None; +} + +void Simulator::LocalMonitor::NotifyLoad() { + if (access_state_ == MonitorAccess::RMW) { + // A non linked load could clear the local monitor. As a result, it's + // most strict to unconditionally clear the local monitor on load. + Clear(); + } +} + +void Simulator::LocalMonitor::NotifyLoadLinked(uintptr_t addr, + TransactionSize size) { + access_state_ = MonitorAccess::RMW; + tagged_addr_ = addr; + size_ = size; +} + +void Simulator::LocalMonitor::NotifyStore() { + if (access_state_ == MonitorAccess::RMW) { + // A non exclusive store could clear the local monitor. As a result, it's + // most strict to unconditionally clear the local monitor on store. + Clear(); + } +} + +bool Simulator::LocalMonitor::NotifyStoreConditional(uintptr_t addr, + TransactionSize size) { + if (access_state_ == MonitorAccess::RMW) { + if (addr == tagged_addr_ && size_ == size) { + Clear(); + return true; + } else { + return false; + } + } else { + DCHECK(access_state_ == MonitorAccess::Open); + return false; + } +} + +Simulator::GlobalMonitor::LinkedAddress::LinkedAddress() + : access_state_(MonitorAccess::Open), + tagged_addr_(0), + next_(nullptr), + prev_(nullptr), + failure_counter_(0) {} + +void Simulator::GlobalMonitor::LinkedAddress::Clear_Locked() { + access_state_ = MonitorAccess::Open; + tagged_addr_ = 0; +} + +void Simulator::GlobalMonitor::LinkedAddress::NotifyLoadLinked_Locked( + uintptr_t addr) { + access_state_ = MonitorAccess::RMW; + tagged_addr_ = addr; +} + +void Simulator::GlobalMonitor::LinkedAddress::NotifyStore_Locked() { + if (access_state_ == MonitorAccess::RMW) { + // A non exclusive store could clear the global monitor. As a result, it's + // most strict to unconditionally clear global monitors on store. + Clear_Locked(); + } +} + +bool Simulator::GlobalMonitor::LinkedAddress::NotifyStoreConditional_Locked( + uintptr_t addr, bool is_requesting_processor) { + if (access_state_ == MonitorAccess::RMW) { + if (is_requesting_processor) { + if (addr == tagged_addr_) { + Clear_Locked(); + // Introduce occasional sc/scd failures. This is to simulate the + // behavior of hardware, which can randomly fail due to background + // cache evictions. + if (failure_counter_++ >= kMaxFailureCounter) { + failure_counter_ = 0; + return false; + } else { + return true; + } + } + } else if ((addr & kExclusiveTaggedAddrMask) == + (tagged_addr_ & kExclusiveTaggedAddrMask)) { + // Check the masked addresses when responding to a successful lock by + // another thread so the implementation is more conservative (i.e. the + // granularity of locking is as large as possible.) + Clear_Locked(); + return false; + } + } + return false; +} + +void Simulator::GlobalMonitor::NotifyLoadLinked_Locked( + uintptr_t addr, LinkedAddress* linked_address) { + linked_address->NotifyLoadLinked_Locked(addr); + PrependProcessor_Locked(linked_address); +} + +void Simulator::GlobalMonitor::NotifyStore_Locked( + LinkedAddress* linked_address) { + // Notify each thread of the store operation. + for (LinkedAddress* iter = head_; iter; iter = iter->next_) { + iter->NotifyStore_Locked(); + } +} + +bool Simulator::GlobalMonitor::NotifyStoreConditional_Locked( + uintptr_t addr, LinkedAddress* linked_address) { + DCHECK(IsProcessorInLinkedList_Locked(linked_address)); + if (linked_address->NotifyStoreConditional_Locked(addr, true)) { + // Notify the other processors that this StoreConditional succeeded. + for (LinkedAddress* iter = head_; iter; iter = iter->next_) { + if (iter != linked_address) { + iter->NotifyStoreConditional_Locked(addr, false); + } + } + return true; + } else { + return false; + } +} + +bool Simulator::GlobalMonitor::IsProcessorInLinkedList_Locked( + LinkedAddress* linked_address) const { + return head_ == linked_address || linked_address->next_ || + linked_address->prev_; +} + +void Simulator::GlobalMonitor::PrependProcessor_Locked( + LinkedAddress* linked_address) { + if (IsProcessorInLinkedList_Locked(linked_address)) { + return; + } + + if (head_) { + head_->prev_ = linked_address; + } + linked_address->prev_ = nullptr; + linked_address->next_ = head_; + head_ = linked_address; +} + +void Simulator::GlobalMonitor::RemoveLinkedAddress( + LinkedAddress* linked_address) { + base::MutexGuard lock_guard(&mutex); + if (!IsProcessorInLinkedList_Locked(linked_address)) { + return; + } + + if (linked_address->prev_) { + linked_address->prev_->next_ = linked_address->next_; + } else { + head_ = linked_address->next_; + } + if (linked_address->next_) { + linked_address->next_->prev_ = linked_address->prev_; + } + linked_address->prev_ = nullptr; + linked_address->next_ = nullptr; +} #undef UNSUPPORTED @@ -7131,5 +7354,3 @@ uintptr_t Simulator::PopAddress() { } // namespace v8 #endif // USE_SIMULATOR - -#endif // V8_TARGET_ARCH_MIPS |