Commit 6525976b authored by Junliang Yan's avatar Junliang Yan Committed by Commit Bot

PPC: fix simulator on race condition

R=joransiu@ca.ibm.com

Change-Id: I7d8f430df2f1f35145df7ba2326b3149d3193a60
Reviewed-on: https://chromium-review.googlesource.com/c/1297487
Commit-Queue: Junliang Yan <jyan@ca.ibm.com>
Reviewed-by: 's avatarJoran Siu <joransiu@ca.ibm.com>
Cr-Commit-Position: refs/heads/master@{#57187}
parent 9bd6e601
......@@ -775,7 +775,6 @@ Simulator::Simulator(Isolate* isolate) : isolate_(isolate) {
}
Simulator::~Simulator() {
global_monitor_.Pointer()->RemoveProcessor(&global_monitor_processor_);
free(stack_);
}
......@@ -871,245 +870,26 @@ void Simulator::TrashCallerSaveRegisters() {
#endif
}
int Simulator::WriteExDW(intptr_t addr, uint64_t value, Instruction* instr) {
base::MutexGuard lock_guard(&global_monitor_.Pointer()->mutex);
if (local_monitor_.NotifyStoreExcl(addr, TransactionSize::Word) &&
global_monitor_.Pointer()->NotifyStoreExcl_Locked(
addr, &global_monitor_processor_)) {
uint64_t* ptr = reinterpret_cast<uint64_t*>(addr);
*ptr = value;
return 0;
} else {
return 1;
}
}
uint64_t Simulator::ReadExDWU(intptr_t addr, Instruction* instr) {
base::MutexGuard lock_guard(&global_monitor_.Pointer()->mutex);
local_monitor_.NotifyLoadExcl(addr, TransactionSize::Word);
global_monitor_.Pointer()->NotifyLoadExcl_Locked(addr,
&global_monitor_processor_);
uint64_t* ptr = reinterpret_cast<uint64_t*>(addr);
return *ptr;
}
uint32_t Simulator::ReadWU(intptr_t addr, Instruction* instr) {
// All supported PPC targets allow unaligned accesses, so we don't need to
// check the alignment here.
base::MutexGuard lock_guard(&global_monitor_.Pointer()->mutex);
local_monitor_.NotifyLoad(addr);
uint32_t* ptr = reinterpret_cast<uint32_t*>(addr);
return *ptr;
}
uint32_t Simulator::ReadExWU(intptr_t addr, Instruction* instr) {
base::MutexGuard lock_guard(&global_monitor_.Pointer()->mutex);
local_monitor_.NotifyLoadExcl(addr, TransactionSize::Word);
global_monitor_.Pointer()->NotifyLoadExcl_Locked(addr,
&global_monitor_processor_);
uint32_t* ptr = reinterpret_cast<uint32_t*>(addr);
return *ptr;
}
int32_t Simulator::ReadW(intptr_t addr, Instruction* instr) {
// All supported PPC targets allow unaligned accesses, so we don't need to
// check the alignment here.
base::MutexGuard lock_guard(&global_monitor_.Pointer()->mutex);
local_monitor_.NotifyLoad(addr);
int32_t* ptr = reinterpret_cast<int32_t*>(addr);
return *ptr;
}
void Simulator::WriteW(intptr_t addr, uint32_t value, Instruction* instr) {
// All supported PPC targets allow unaligned accesses, so we don't need to
// check the alignment here.
base::MutexGuard lock_guard(&global_monitor_.Pointer()->mutex);
local_monitor_.NotifyStore(addr);
global_monitor_.Pointer()->NotifyStore_Locked(addr,
&global_monitor_processor_);
uint32_t* ptr = reinterpret_cast<uint32_t*>(addr);
*ptr = value;
return;
}
int Simulator::WriteExW(intptr_t addr, uint32_t value, Instruction* instr) {
base::MutexGuard lock_guard(&global_monitor_.Pointer()->mutex);
if (local_monitor_.NotifyStoreExcl(addr, TransactionSize::Word) &&
global_monitor_.Pointer()->NotifyStoreExcl_Locked(
addr, &global_monitor_processor_)) {
uint32_t* ptr = reinterpret_cast<uint32_t*>(addr);
*ptr = value;
return 0;
} else {
return 1;
#define GENERATE_RW_FUNC(size, type) \
type Simulator::Read##size(uintptr_t addr) { \
type value; \
Read(addr, &value); \
return value; \
} \
type Simulator::ReadEx##size(uintptr_t addr) { \
type value; \
ReadEx(addr, &value); \
return value; \
} \
void Simulator::Write##size(uintptr_t addr, type value) { \
Write(addr, value); \
} \
int32_t Simulator::WriteEx##size(uintptr_t addr, type value) { \
return WriteEx(addr, value); \
}
}
void Simulator::WriteW(intptr_t addr, int32_t value, Instruction* instr) {
// All supported PPC targets allow unaligned accesses, so we don't need to
// check the alignment here.
base::MutexGuard lock_guard(&global_monitor_.Pointer()->mutex);
local_monitor_.NotifyStore(addr);
global_monitor_.Pointer()->NotifyStore_Locked(addr,
&global_monitor_processor_);
int32_t* ptr = reinterpret_cast<int32_t*>(addr);
*ptr = value;
return;
}
uint16_t Simulator::ReadHU(intptr_t addr, Instruction* instr) {
// All supported PPC targets allow unaligned accesses, so we don't need to
// check the alignment here.
base::MutexGuard lock_guard(&global_monitor_.Pointer()->mutex);
local_monitor_.NotifyLoad(addr);
uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
return *ptr;
}
uint16_t Simulator::ReadExHU(intptr_t addr, Instruction* instr) {
base::MutexGuard lock_guard(&global_monitor_.Pointer()->mutex);
local_monitor_.NotifyLoadExcl(addr, TransactionSize::HalfWord);
global_monitor_.Pointer()->NotifyLoadExcl_Locked(addr,
&global_monitor_processor_);
uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
return *ptr;
}
int16_t Simulator::ReadH(intptr_t addr, Instruction* instr) {
// All supported PPC targets allow unaligned accesses, so we don't need to
// check the alignment here.
base::MutexGuard lock_guard(&global_monitor_.Pointer()->mutex);
local_monitor_.NotifyLoad(addr);
int16_t* ptr = reinterpret_cast<int16_t*>(addr);
return *ptr;
}
void Simulator::WriteH(intptr_t addr, uint16_t value, Instruction* instr) {
// All supported PPC targets allow unaligned accesses, so we don't need to
// check the alignment here.
base::MutexGuard lock_guard(&global_monitor_.Pointer()->mutex);
local_monitor_.NotifyStore(addr);
global_monitor_.Pointer()->NotifyStore_Locked(addr,
&global_monitor_processor_);
uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
*ptr = value;
return;
}
void Simulator::WriteH(intptr_t addr, int16_t value, Instruction* instr) {
// All supported PPC targets allow unaligned accesses, so we don't need to
// check the alignment here.
base::MutexGuard lock_guard(&global_monitor_.Pointer()->mutex);
local_monitor_.NotifyStore(addr);
global_monitor_.Pointer()->NotifyStore_Locked(addr,
&global_monitor_processor_);
int16_t* ptr = reinterpret_cast<int16_t*>(addr);
*ptr = value;
return;
}
int Simulator::WriteExH(intptr_t addr, uint16_t value, Instruction* instr) {
base::MutexGuard lock_guard(&global_monitor_.Pointer()->mutex);
if (local_monitor_.NotifyStoreExcl(addr, TransactionSize::HalfWord) &&
global_monitor_.Pointer()->NotifyStoreExcl_Locked(
addr, &global_monitor_processor_)) {
uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
*ptr = value;
return 0;
} else {
return 1;
}
}
uint8_t Simulator::ReadBU(intptr_t addr) {
// All supported PPC targets allow unaligned accesses, so we don't need to
// check the alignment here.
base::MutexGuard lock_guard(&global_monitor_.Pointer()->mutex);
local_monitor_.NotifyLoad(addr);
uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
return *ptr;
}
int8_t Simulator::ReadB(intptr_t addr) {
// All supported PPC targets allow unaligned accesses, so we don't need to
// check the alignment here.
base::MutexGuard lock_guard(&global_monitor_.Pointer()->mutex);
local_monitor_.NotifyLoad(addr);
int8_t* ptr = reinterpret_cast<int8_t*>(addr);
return *ptr;
}
uint8_t Simulator::ReadExBU(intptr_t addr) {
base::MutexGuard lock_guard(&global_monitor_.Pointer()->mutex);
local_monitor_.NotifyLoadExcl(addr, TransactionSize::Byte);
global_monitor_.Pointer()->NotifyLoadExcl_Locked(addr,
&global_monitor_processor_);
uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
return *ptr;
}
void Simulator::WriteB(intptr_t addr, uint8_t value) {
// All supported PPC targets allow unaligned accesses, so we don't need to
// check the alignment here.
base::MutexGuard lock_guard(&global_monitor_.Pointer()->mutex);
local_monitor_.NotifyStore(addr);
global_monitor_.Pointer()->NotifyStore_Locked(addr,
&global_monitor_processor_);
uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
*ptr = value;
}
void Simulator::WriteB(intptr_t addr, int8_t value) {
// All supported PPC targets allow unaligned accesses, so we don't need to
// check the alignment here.
base::MutexGuard lock_guard(&global_monitor_.Pointer()->mutex);
local_monitor_.NotifyStore(addr);
global_monitor_.Pointer()->NotifyStore_Locked(addr,
&global_monitor_processor_);
int8_t* ptr = reinterpret_cast<int8_t*>(addr);
*ptr = value;
}
int Simulator::WriteExB(intptr_t addr, uint8_t value) {
base::MutexGuard lock_guard(&global_monitor_.Pointer()->mutex);
if (local_monitor_.NotifyStoreExcl(addr, TransactionSize::Byte) &&
global_monitor_.Pointer()->NotifyStoreExcl_Locked(
addr, &global_monitor_processor_)) {
uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
*ptr = value;
return 0;
} else {
return 1;
}
}
intptr_t* Simulator::ReadDW(intptr_t addr) {
// All supported PPC targets allow unaligned accesses, so we don't need to
// check the alignment here.
base::MutexGuard lock_guard(&global_monitor_.Pointer()->mutex);
local_monitor_.NotifyLoad(addr);
intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
return ptr;
}
void Simulator::WriteDW(intptr_t addr, int64_t value) {
// All supported PPC targets allow unaligned accesses, so we don't need to
// check the alignment here.
base::MutexGuard lock_guard(&global_monitor_.Pointer()->mutex);
local_monitor_.NotifyStore(addr);
global_monitor_.Pointer()->NotifyStore_Locked(addr,
&global_monitor_processor_);
int64_t* ptr = reinterpret_cast<int64_t*>(addr);
*ptr = value;
return;
}
RW_VAR_LIST(GENERATE_RW_FUNC);
#undef GENERATE_RW_FUNC
// Returns the limit of the stack area to enable checking for stack overflows.
uintptr_t Simulator::StackLimit(uintptr_t c_limit) const {
......@@ -2138,7 +1918,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
int rb = instr->RBValue();
intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
intptr_t rb_val = get_register(rb);
int32_t val = ReadW(ra_val + rb_val, instr);
int32_t val = ReadW(ra_val + rb_val);
float* fptr = reinterpret_cast<float*>(&val);
#if V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64
// Conversion using double changes sNan to qNan on ia32/x64
......@@ -2166,8 +1946,8 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
int rb = instr->RBValue();
intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
intptr_t rb_val = get_register(rb);
int64_t* dptr = reinterpret_cast<int64_t*>(ReadDW(ra_val + rb_val));
set_d_register(frt, *dptr);
int64_t dptr = ReadDW(ra_val + rb_val);
set_d_register(frt, dptr);
if (opcode == LFDUX) {
DCHECK_NE(ra, 0);
set_register(ra, ra_val + rb_val);
......@@ -2197,7 +1977,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
#else
p = reinterpret_cast<int32_t*>(&frs_val);
#endif
WriteW(ra_val + rb_val, *p, instr);
WriteW(ra_val + rb_val, *p);
if (opcode == STFSUX) {
DCHECK_NE(ra, 0);
set_register(ra, ra_val + rb_val);
......@@ -2265,7 +2045,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
int rt = instr->RTValue();
intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
int offset = SIGN_EXT_IMM16(instr->Bits(15, 0));
set_register(rt, ReadWU(ra_val + offset, instr));
set_register(rt, ReadWU(ra_val + offset));
if (opcode == LWZU) {
DCHECK_NE(ra, 0);
set_register(ra, ra_val + offset);
......@@ -2294,7 +2074,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
int32_t rs_val = get_register(rs);
int offset = SIGN_EXT_IMM16(instr->Bits(15, 0));
WriteW(ra_val + offset, rs_val, instr);
WriteW(ra_val + offset, rs_val);
if (opcode == STWU) {
DCHECK_NE(ra, 0);
set_register(ra, ra_val + offset);
......@@ -2330,7 +2110,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
int16_t rs_val = get_register(rs);
intptr_t rb_val = get_register(rb);
SetCR0(WriteExH(ra_val + rb_val, rs_val, instr));
SetCR0(WriteExH(ra_val + rb_val, rs_val));
break;
}
case STWCX: {
......@@ -2340,7 +2120,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
int32_t rs_val = get_register(rs);
intptr_t rb_val = get_register(rb);
SetCR0(WriteExW(ra_val + rb_val, rs_val, instr));
SetCR0(WriteExW(ra_val + rb_val, rs_val));
break;
}
case STDCX: {
......@@ -2350,7 +2130,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
int64_t rs_val = get_register(rs);
intptr_t rb_val = get_register(rb);
SetCR0(WriteExDW(ra_val + rb_val, rs_val, instr));
SetCR0(WriteExDW(ra_val + rb_val, rs_val));
break;
}
case TW: {
......@@ -2964,7 +2744,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
int32_t rs_val = get_register(rs);
intptr_t rb_val = get_register(rb);
WriteW(ra_val + rb_val, rs_val, instr);
WriteW(ra_val + rb_val, rs_val);
if (opcode == STWUX) {
DCHECK_NE(ra, 0);
set_register(ra, ra_val + rb_val);
......@@ -2994,7 +2774,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
int16_t rs_val = get_register(rs);
intptr_t rb_val = get_register(rb);
WriteH(ra_val + rb_val, rs_val, instr);
WriteH(ra_val + rb_val, rs_val);
if (opcode == STHUX) {
DCHECK_NE(ra, 0);
set_register(ra, ra_val + rb_val);
......@@ -3008,7 +2788,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
int rb = instr->RBValue();
intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
intptr_t rb_val = get_register(rb);
set_register(rt, ReadWU(ra_val + rb_val, instr));
set_register(rt, ReadWU(ra_val + rb_val));
if (opcode == LWZUX) {
DCHECK(ra != 0 && ra != rt);
set_register(ra, ra_val + rb_val);
......@@ -3022,7 +2802,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
int rb = instr->RBValue();
intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
intptr_t rb_val = get_register(rb);
set_register(rt, ReadW(ra_val + rb_val, instr));
set_register(rt, ReadW(ra_val + rb_val));
break;
}
case LDX:
......@@ -3032,8 +2812,8 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
int rb = instr->RBValue();
intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
intptr_t rb_val = get_register(rb);
intptr_t* result = ReadDW(ra_val + rb_val);
set_register(rt, *result);
intptr_t result = ReadDW(ra_val + rb_val);
set_register(rt, result);
if (opcode == LDUX) {
DCHECK(ra != 0 && ra != rt);
set_register(ra, ra_val + rb_val);
......@@ -3077,7 +2857,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
int rb = instr->RBValue();
intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
intptr_t rb_val = get_register(rb);
set_register(rt, ReadHU(ra_val + rb_val, instr) & 0xFFFF);
set_register(rt, ReadHU(ra_val + rb_val) & 0xFFFF);
if (opcode == LHZUX) {
DCHECK(ra != 0 && ra != rt);
set_register(ra, ra_val + rb_val);
......@@ -3090,7 +2870,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
int rb = instr->RBValue();
intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
intptr_t rb_val = get_register(rb);
set_register(rt, ReadH(ra_val + rb_val, instr));
set_register(rt, ReadH(ra_val + rb_val));
break;
}
case LBARX: {
......@@ -3108,7 +2888,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
int rb = instr->RBValue();
intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
intptr_t rb_val = get_register(rb);
set_register(rt, ReadExHU(ra_val + rb_val, instr));
set_register(rt, ReadExHU(ra_val + rb_val));
break;
}
case LWARX: {
......@@ -3117,7 +2897,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
int rb = instr->RBValue();
intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
intptr_t rb_val = get_register(rb);
set_register(rt, ReadExWU(ra_val + rb_val, instr));
set_register(rt, ReadExWU(ra_val + rb_val));
break;
}
case LDARX: {
......@@ -3126,7 +2906,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
int rb = instr->RBValue();
intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
intptr_t rb_val = get_register(rb);
set_register(rt, ReadExDWU(ra_val + rb_val, instr));
set_register(rt, ReadExDWU(ra_val + rb_val));
break;
}
case DCBF: {
......@@ -3167,7 +2947,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
int rt = instr->RTValue();
intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
int offset = SIGN_EXT_IMM16(instr->Bits(15, 0));
uintptr_t result = ReadHU(ra_val + offset, instr) & 0xFFFF;
uintptr_t result = ReadHU(ra_val + offset) & 0xFFFF;
set_register(rt, result);
if (opcode == LHZU) {
set_register(ra, ra_val + offset);
......@@ -3181,7 +2961,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
int rt = instr->RTValue();
intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
int offset = SIGN_EXT_IMM16(instr->Bits(15, 0));
intptr_t result = ReadH(ra_val + offset, instr);
intptr_t result = ReadH(ra_val + offset);
set_register(rt, result);
if (opcode == LHAU) {
set_register(ra, ra_val + offset);
......@@ -3196,7 +2976,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
int16_t rs_val = get_register(rs);
int offset = SIGN_EXT_IMM16(instr->Bits(15, 0));
WriteH(ra_val + offset, rs_val, instr);
WriteH(ra_val + offset, rs_val);
if (opcode == STHU) {
DCHECK_NE(ra, 0);
set_register(ra, ra_val + offset);
......@@ -3216,7 +2996,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
int ra = instr->RAValue();
int32_t offset = SIGN_EXT_IMM16(instr->Bits(15, 0));
intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
int32_t val = ReadW(ra_val + offset, instr);
int32_t val = ReadW(ra_val + offset);
float* fptr = reinterpret_cast<float*>(&val);
#if V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64
// Conversion using double changes sNan to qNan on ia32/x64
......@@ -3244,8 +3024,8 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
int ra = instr->RAValue();
int32_t offset = SIGN_EXT_IMM16(instr->Bits(15, 0));
intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
int64_t* dptr = reinterpret_cast<int64_t*>(ReadDW(ra_val + offset));
set_d_register(frt, *dptr);
int64_t dptr = ReadDW(ra_val + offset);
set_d_register(frt, dptr);
if (opcode == LFDU) {
DCHECK_NE(ra, 0);
set_register(ra, ra_val + offset);
......@@ -3275,7 +3055,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
#else
p = reinterpret_cast<int32_t*>(&frs_val);
#endif
WriteW(ra_val + offset, *p, instr);
WriteW(ra_val + offset, *p);
if (opcode == STFSU) {
DCHECK_NE(ra, 0);
set_register(ra, ra_val + offset);
......@@ -3849,19 +3629,19 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
int offset = SIGN_EXT_IMM16(instr->Bits(15, 0) & ~3);
switch (instr->Bits(1, 0)) {
case 0: { // ld
intptr_t* result = ReadDW(ra_val + offset);
set_register(rt, *result);
intptr_t result = ReadDW(ra_val + offset);
set_register(rt, result);
break;
}
case 1: { // ldu
intptr_t* result = ReadDW(ra_val + offset);
set_register(rt, *result);
intptr_t result = ReadDW(ra_val + offset);
set_register(rt, result);
DCHECK_NE(ra, 0);
set_register(ra, ra_val + offset);
break;
}
case 2: { // lwa
intptr_t result = ReadW(ra_val + offset, instr);
intptr_t result = ReadW(ra_val + offset);
set_register(rt, result);
break;
}
......@@ -4189,170 +3969,65 @@ uintptr_t Simulator::PopAddress() {
return address;
}
Simulator::LocalMonitor::LocalMonitor()
Simulator::GlobalMonitor::GlobalMonitor()
: access_state_(MonitorAccess::Open),
tagged_addr_(0),
size_(TransactionSize::None) {}
size_(TransactionSize::None),
thread_id_(ThreadId::Invalid()) {}
void Simulator::LocalMonitor::Clear() {
void Simulator::GlobalMonitor::Clear() {
access_state_ = MonitorAccess::Open;
tagged_addr_ = 0;
size_ = TransactionSize::None;
thread_id_ = ThreadId::Invalid();
}
void Simulator::LocalMonitor::NotifyLoad(int32_t addr) {
if (access_state_ == MonitorAccess::Exclusive) {
// A load could cause a cache eviction which will affect the monitor. As a
// result, it's most strict to unconditionally clear the local monitor on
// load.
Clear();
}
}
void Simulator::LocalMonitor::NotifyLoadExcl(int32_t addr,
TransactionSize size) {
void Simulator::GlobalMonitor::NotifyLoadExcl(uintptr_t addr,
TransactionSize size,
ThreadId thread_id) {
// TODO(s390): By using Global Monitors, we are effectively limiting one
// active reservation across all processors. This would potentially serialize
// parallel threads executing load&reserve + store conditional on unrelated
// memory. Technically, this implementation would still make the simulator
// adhere to the spec, but seems overly heavy-handed.
access_state_ = MonitorAccess::Exclusive;
tagged_addr_ = addr;
size_ = size;
thread_id_ = thread_id;
}
void Simulator::LocalMonitor::NotifyStore(int32_t addr) {
if (access_state_ == MonitorAccess::Exclusive) {
// A store could cause a cache eviction which will affect the
// monitor. As a result, it's most strict to unconditionally clear the
// local monitor on store.
Clear();
}
}
bool Simulator::LocalMonitor::NotifyStoreExcl(int32_t addr,
TransactionSize size) {
void Simulator::GlobalMonitor::NotifyStore(uintptr_t addr, TransactionSize size,
ThreadId thread_id) {
if (access_state_ == MonitorAccess::Exclusive) {
if (addr == tagged_addr_ && size_ == size) {
// Calculate if the transaction has been overlapped
uintptr_t transaction_start = addr;
uintptr_t transaction_end = addr + static_cast<uintptr_t>(size);
uintptr_t exclusive_transaction_start = tagged_addr_;
uintptr_t exclusive_transaction_end =
tagged_addr_ + static_cast<uintptr_t>(size_);
bool is_not_overlapped = transaction_end < exclusive_transaction_start ||
exclusive_transaction_end < transaction_start;
if (!is_not_overlapped && !thread_id_.Equals(thread_id)) {
Clear();
return true;
} else {
Clear();
return false;
}
} else {
DCHECK(access_state_ == MonitorAccess::Open);
return false;
}
}
Simulator::GlobalMonitor::Processor::Processor()
: access_state_(MonitorAccess::Open),
tagged_addr_(0),
next_(nullptr),
prev_(nullptr) {}
void Simulator::GlobalMonitor::Processor::Clear_Locked() {
access_state_ = MonitorAccess::Open;
tagged_addr_ = 0;
}
void Simulator::GlobalMonitor::Processor::NotifyLoadExcl_Locked(int32_t addr) {
access_state_ = MonitorAccess::Exclusive;
tagged_addr_ = addr;
}
void Simulator::GlobalMonitor::Processor::NotifyStore_Locked(
int32_t addr, bool is_requesting_processor) {
if (access_state_ == MonitorAccess::Exclusive) {
// It is possible that a store caused a cache eviction,
// which can affect the montior, so conservatively,
// we always clear the monitor.
Clear_Locked();
}
}
bool Simulator::GlobalMonitor::Processor::NotifyStoreExcl_Locked(
int32_t addr, bool is_requesting_processor) {
if (access_state_ == MonitorAccess::Exclusive) {
if (is_requesting_processor) {
if (addr == tagged_addr_) {
Clear_Locked();
return true;
}
} else if (addr == tagged_addr_) {
Clear_Locked();
return false;
}
}
return false;
}
Simulator::GlobalMonitor::GlobalMonitor() : head_(nullptr) {}
void Simulator::GlobalMonitor::NotifyLoadExcl_Locked(int32_t addr,
Processor* processor) {
processor->NotifyLoadExcl_Locked(addr);
PrependProcessor_Locked(processor);
}
void Simulator::GlobalMonitor::NotifyStore_Locked(int32_t addr,
Processor* processor) {
// Notify each processor of the store operation.
for (Processor* iter = head_; iter; iter = iter->next_) {
bool is_requesting_processor = iter == processor;
iter->NotifyStore_Locked(addr, is_requesting_processor);
}
}
bool Simulator::GlobalMonitor::NotifyStoreExcl_Locked(int32_t addr,
Processor* processor) {
DCHECK(IsProcessorInLinkedList_Locked(processor));
if (processor->NotifyStoreExcl_Locked(addr, true)) {
// Notify the other processors that this StoreExcl succeeded.
for (Processor* iter = head_; iter; iter = iter->next_) {
if (iter != processor) {
iter->NotifyStoreExcl_Locked(addr, false);
}
}
return true;
} else {
return false;
}
}
bool Simulator::GlobalMonitor::IsProcessorInLinkedList_Locked(
Processor* processor) const {
return head_ == processor || processor->next_ || processor->prev_;
}
void Simulator::GlobalMonitor::PrependProcessor_Locked(Processor* processor) {
if (IsProcessorInLinkedList_Locked(processor)) {
return;
}
if (head_) {
head_->prev_ = processor;
}
processor->prev_ = nullptr;
processor->next_ = head_;
head_ = processor;
}
void Simulator::GlobalMonitor::RemoveProcessor(Processor* processor) {
base::MutexGuard lock_guard(&mutex);
if (!IsProcessorInLinkedList_Locked(processor)) {
return;
}
if (processor->prev_) {
processor->prev_->next_ = processor->next_;
} else {
head_ = processor->next_;
}
if (processor->next_) {
processor->next_->prev_ = processor->prev_;
}
processor->prev_ = nullptr;
processor->next_ = nullptr;
bool Simulator::GlobalMonitor::NotifyStoreExcl(uintptr_t addr,
TransactionSize size,
ThreadId thread_id) {
bool permission = access_state_ == MonitorAccess::Exclusive &&
addr == tagged_addr_ && size_ == size &&
thread_id_.Equals(thread_id);
// The reservation is cleared if the processor holding the reservation
// executes a store conditional instruction to any address.
Clear();
return permission;
}
} // namespace internal
} // namespace v8
#undef SScanF
#endif // USE_SIMULATOR
#endif // V8_TARGET_ARCH_PPC
......@@ -13,6 +13,8 @@
#define V8_PPC_SIMULATOR_PPC_H_
#include "src/allocation.h"
#include "src/base/lazy-instance.h"
#include "src/base/platform/mutex.h"
#if defined(USE_SIMULATOR)
// Running with a simulator.
......@@ -241,49 +243,61 @@ class Simulator : public SimulatorBase {
void PrintStopInfo(uint32_t code);
// Read and write memory.
inline uint8_t ReadBU(intptr_t addr);
inline uint8_t ReadExBU(intptr_t addr);
inline int8_t ReadB(intptr_t addr);
inline void WriteB(intptr_t addr, uint8_t value);
inline int WriteExB(intptr_t addr, uint8_t value);
inline void WriteB(intptr_t addr, int8_t value);
inline uint16_t ReadHU(intptr_t addr, Instruction* instr);
inline uint16_t ReadExHU(intptr_t addr, Instruction* instr);
inline int16_t ReadH(intptr_t addr, Instruction* instr);
// Note: Overloaded on the sign of the value.
inline void WriteH(intptr_t addr, uint16_t value, Instruction* instr);
inline int WriteExH(intptr_t addr, uint16_t value, Instruction* instr);
inline void WriteH(intptr_t addr, int16_t value, Instruction* instr);
inline uint32_t ReadWU(intptr_t addr, Instruction* instr);
inline uint32_t ReadExWU(intptr_t addr, Instruction* instr);
inline int32_t ReadW(intptr_t addr, Instruction* instr);
inline void WriteW(intptr_t addr, uint32_t value, Instruction* instr);
inline int WriteExW(intptr_t addr, uint32_t value, Instruction* instr);
inline void WriteW(intptr_t addr, int32_t value, Instruction* instr);
intptr_t* ReadDW(intptr_t addr);
void WriteDW(intptr_t addr, int64_t value);
inline int WriteExDW(intptr_t addr, uint64_t value, Instruction* instr);
inline uint64_t ReadExDWU(intptr_t addr, Instruction* instr);
template <typename T>
inline void Read(uintptr_t address, T* value) {
base::MutexGuard lock_guard(&global_monitor_.Pointer()->mutex);
memcpy(value, reinterpret_cast<const char*>(address), sizeof(T));
}
template <typename T>
inline void ReadEx(uintptr_t address, T* value) {
base::MutexGuard lock_guard(&global_monitor_.Pointer()->mutex);
global_monitor_.Pointer()->NotifyLoadExcl(
address, static_cast<TransactionSize>(sizeof(T)),
isolate_->thread_id());
memcpy(value, reinterpret_cast<const char*>(address), sizeof(T));
}
template <typename T>
inline void Write(uintptr_t address, T value) {
base::MutexGuard lock_guard(&global_monitor_.Pointer()->mutex);
global_monitor_.Pointer()->NotifyStore(
address, static_cast<TransactionSize>(sizeof(T)),
isolate_->thread_id());
memcpy(reinterpret_cast<char*>(address), &value, sizeof(T));
}
template <typename T>
inline int32_t WriteEx(uintptr_t address, T value) {
base::MutexGuard lock_guard(&global_monitor_.Pointer()->mutex);
if (global_monitor_.Pointer()->NotifyStoreExcl(
address, static_cast<TransactionSize>(sizeof(T)),
isolate_->thread_id())) {
memcpy(reinterpret_cast<char*>(address), &value, sizeof(T));
return 0;
} else {
return 1;
}
}
#define RW_VAR_LIST(V) \
V(DWU, uint64_t) \
V(DW, int64_t) \
V(WU, uint32_t) \
V(W, int32_t) V(HU, uint16_t) V(H, int16_t) V(BU, uint8_t) V(B, int8_t)
#define GENERATE_RW_FUNC(size, type) \
inline type Read##size(uintptr_t addr); \
inline type ReadEx##size(uintptr_t addr); \
inline void Write##size(uintptr_t addr, type value); \
inline int32_t WriteEx##size(uintptr_t addr, type value);
RW_VAR_LIST(GENERATE_RW_FUNC);
#undef GENERATE_RW_FUNC
void Trace(Instruction* instr);
void SetCR0(intptr_t result, bool setSO = false);
void ExecuteBranchConditional(Instruction* instr, BCType type);
void ExecuteExt1(Instruction* instr);
bool ExecuteExt2_10bit_part1(Instruction* instr);
bool ExecuteExt2_10bit_part2(Instruction* instr);
bool ExecuteExt2_9bit_part1(Instruction* instr);
bool ExecuteExt2_9bit_part2(Instruction* instr);
void ExecuteExt2_5bit(Instruction* instr);
void ExecuteExt2(Instruction* instr);
void ExecuteExt3(Instruction* instr);
void ExecuteExt4(Instruction* instr);
#if V8_TARGET_ARCH_PPC64
void ExecuteExt5(Instruction* instr);
#endif
void ExecuteExt6(Instruction* instr);
void ExecuteGeneric(Instruction* instr);
void SetFPSCR(int bit) { fp_condition_reg_ |= (1 << (31 - bit)); }
......@@ -364,71 +378,31 @@ class Simulator : public SimulatorBase {
Byte = 1,
HalfWord = 2,
Word = 4,
};
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_;
DWord = 8,
};
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_;
};
// 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);
void NotifyLoadExcl(uintptr_t addr, TransactionSize size,
ThreadId thread_id);
void NotifyStore(uintptr_t addr, TransactionSize size, ThreadId thread_id);
bool NotifyStoreExcl(uintptr_t addr, TransactionSize size,
ThreadId thread_id);
private:
bool IsProcessorInLinkedList_Locked(Processor* processor) const;
void PrependProcessor_Locked(Processor* processor);
void Clear();
Processor* head_;
MonitorAccess access_state_;
uintptr_t tagged_addr_;
TransactionSize size_;
ThreadId thread_id_;
};
LocalMonitor local_monitor_;
GlobalMonitor::Processor global_monitor_processor_;
static base::LazyInstance<GlobalMonitor>::type global_monitor_;
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment