aboutsummaryrefslogtreecommitdiff
path: root/deps/v8/src/mips/simulator-mips.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/mips/simulator-mips.cc')
-rw-r--r--deps/v8/src/mips/simulator-mips.cc309
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