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) { ...@@ -775,7 +775,6 @@ Simulator::Simulator(Isolate* isolate) : isolate_(isolate) {
} }
Simulator::~Simulator() { Simulator::~Simulator() {
global_monitor_.Pointer()->RemoveProcessor(&global_monitor_processor_);
free(stack_); free(stack_);
} }
...@@ -871,245 +870,26 @@ void Simulator::TrashCallerSaveRegisters() { ...@@ -871,245 +870,26 @@ void Simulator::TrashCallerSaveRegisters() {
#endif #endif
} }
int Simulator::WriteExDW(intptr_t addr, uint64_t value, Instruction* instr) { #define GENERATE_RW_FUNC(size, type) \
base::MutexGuard lock_guard(&global_monitor_.Pointer()->mutex); type Simulator::Read##size(uintptr_t addr) { \
if (local_monitor_.NotifyStoreExcl(addr, TransactionSize::Word) && type value; \
global_monitor_.Pointer()->NotifyStoreExcl_Locked( Read(addr, &value); \
addr, &global_monitor_processor_)) { return value; \
uint64_t* ptr = reinterpret_cast<uint64_t*>(addr); } \
*ptr = value; type Simulator::ReadEx##size(uintptr_t addr) { \
return 0; type value; \
} else { ReadEx(addr, &value); \
return 1; return value; \
} } \
} void Simulator::Write##size(uintptr_t addr, type value) { \
Write(addr, value); \
uint64_t Simulator::ReadExDWU(intptr_t addr, Instruction* instr) { } \
base::MutexGuard lock_guard(&global_monitor_.Pointer()->mutex); int32_t Simulator::WriteEx##size(uintptr_t addr, type value) { \
local_monitor_.NotifyLoadExcl(addr, TransactionSize::Word); return WriteEx(addr, value); \
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;
} }
}
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. // Returns the limit of the stack area to enable checking for stack overflows.
uintptr_t Simulator::StackLimit(uintptr_t c_limit) const { uintptr_t Simulator::StackLimit(uintptr_t c_limit) const {
...@@ -2138,7 +1918,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) { ...@@ -2138,7 +1918,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
int rb = instr->RBValue(); int rb = instr->RBValue();
intptr_t ra_val = ra == 0 ? 0 : get_register(ra); intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
intptr_t rb_val = get_register(rb); 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); float* fptr = reinterpret_cast<float*>(&val);
#if V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64 #if V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64
// Conversion using double changes sNan to qNan on ia32/x64 // Conversion using double changes sNan to qNan on ia32/x64
...@@ -2166,8 +1946,8 @@ void Simulator::ExecuteGeneric(Instruction* instr) { ...@@ -2166,8 +1946,8 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
int rb = instr->RBValue(); int rb = instr->RBValue();
intptr_t ra_val = ra == 0 ? 0 : get_register(ra); intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
intptr_t rb_val = get_register(rb); intptr_t rb_val = get_register(rb);
int64_t* dptr = reinterpret_cast<int64_t*>(ReadDW(ra_val + rb_val)); int64_t dptr = ReadDW(ra_val + rb_val);
set_d_register(frt, *dptr); set_d_register(frt, dptr);
if (opcode == LFDUX) { if (opcode == LFDUX) {
DCHECK_NE(ra, 0); DCHECK_NE(ra, 0);
set_register(ra, ra_val + rb_val); set_register(ra, ra_val + rb_val);
...@@ -2197,7 +1977,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) { ...@@ -2197,7 +1977,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
#else #else
p = reinterpret_cast<int32_t*>(&frs_val); p = reinterpret_cast<int32_t*>(&frs_val);
#endif #endif
WriteW(ra_val + rb_val, *p, instr); WriteW(ra_val + rb_val, *p);
if (opcode == STFSUX) { if (opcode == STFSUX) {
DCHECK_NE(ra, 0); DCHECK_NE(ra, 0);
set_register(ra, ra_val + rb_val); set_register(ra, ra_val + rb_val);
...@@ -2265,7 +2045,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) { ...@@ -2265,7 +2045,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
int rt = instr->RTValue(); int rt = instr->RTValue();
intptr_t ra_val = ra == 0 ? 0 : get_register(ra); intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
int offset = SIGN_EXT_IMM16(instr->Bits(15, 0)); 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) { if (opcode == LWZU) {
DCHECK_NE(ra, 0); DCHECK_NE(ra, 0);
set_register(ra, ra_val + offset); set_register(ra, ra_val + offset);
...@@ -2294,7 +2074,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) { ...@@ -2294,7 +2074,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
intptr_t ra_val = ra == 0 ? 0 : get_register(ra); intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
int32_t rs_val = get_register(rs); int32_t rs_val = get_register(rs);
int offset = SIGN_EXT_IMM16(instr->Bits(15, 0)); 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) { if (opcode == STWU) {
DCHECK_NE(ra, 0); DCHECK_NE(ra, 0);
set_register(ra, ra_val + offset); set_register(ra, ra_val + offset);
...@@ -2330,7 +2110,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) { ...@@ -2330,7 +2110,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
intptr_t ra_val = ra == 0 ? 0 : get_register(ra); intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
int16_t rs_val = get_register(rs); int16_t rs_val = get_register(rs);
intptr_t rb_val = get_register(rb); 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; break;
} }
case STWCX: { case STWCX: {
...@@ -2340,7 +2120,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) { ...@@ -2340,7 +2120,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
intptr_t ra_val = ra == 0 ? 0 : get_register(ra); intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
int32_t rs_val = get_register(rs); int32_t rs_val = get_register(rs);
intptr_t rb_val = get_register(rb); 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; break;
} }
case STDCX: { case STDCX: {
...@@ -2350,7 +2130,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) { ...@@ -2350,7 +2130,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
intptr_t ra_val = ra == 0 ? 0 : get_register(ra); intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
int64_t rs_val = get_register(rs); int64_t rs_val = get_register(rs);
intptr_t rb_val = get_register(rb); 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; break;
} }
case TW: { case TW: {
...@@ -2964,7 +2744,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) { ...@@ -2964,7 +2744,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
intptr_t ra_val = ra == 0 ? 0 : get_register(ra); intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
int32_t rs_val = get_register(rs); int32_t rs_val = get_register(rs);
intptr_t rb_val = get_register(rb); 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) { if (opcode == STWUX) {
DCHECK_NE(ra, 0); DCHECK_NE(ra, 0);
set_register(ra, ra_val + rb_val); set_register(ra, ra_val + rb_val);
...@@ -2994,7 +2774,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) { ...@@ -2994,7 +2774,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
intptr_t ra_val = ra == 0 ? 0 : get_register(ra); intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
int16_t rs_val = get_register(rs); int16_t rs_val = get_register(rs);
intptr_t rb_val = get_register(rb); 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) { if (opcode == STHUX) {
DCHECK_NE(ra, 0); DCHECK_NE(ra, 0);
set_register(ra, ra_val + rb_val); set_register(ra, ra_val + rb_val);
...@@ -3008,7 +2788,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) { ...@@ -3008,7 +2788,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
int rb = instr->RBValue(); int rb = instr->RBValue();
intptr_t ra_val = ra == 0 ? 0 : get_register(ra); intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
intptr_t rb_val = get_register(rb); 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) { if (opcode == LWZUX) {
DCHECK(ra != 0 && ra != rt); DCHECK(ra != 0 && ra != rt);
set_register(ra, ra_val + rb_val); set_register(ra, ra_val + rb_val);
...@@ -3022,7 +2802,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) { ...@@ -3022,7 +2802,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
int rb = instr->RBValue(); int rb = instr->RBValue();
intptr_t ra_val = ra == 0 ? 0 : get_register(ra); intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
intptr_t rb_val = get_register(rb); 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; break;
} }
case LDX: case LDX:
...@@ -3032,8 +2812,8 @@ void Simulator::ExecuteGeneric(Instruction* instr) { ...@@ -3032,8 +2812,8 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
int rb = instr->RBValue(); int rb = instr->RBValue();
intptr_t ra_val = ra == 0 ? 0 : get_register(ra); intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
intptr_t rb_val = get_register(rb); intptr_t rb_val = get_register(rb);
intptr_t* result = ReadDW(ra_val + rb_val); intptr_t result = ReadDW(ra_val + rb_val);
set_register(rt, *result); set_register(rt, result);
if (opcode == LDUX) { if (opcode == LDUX) {
DCHECK(ra != 0 && ra != rt); DCHECK(ra != 0 && ra != rt);
set_register(ra, ra_val + rb_val); set_register(ra, ra_val + rb_val);
...@@ -3077,7 +2857,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) { ...@@ -3077,7 +2857,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
int rb = instr->RBValue(); int rb = instr->RBValue();
intptr_t ra_val = ra == 0 ? 0 : get_register(ra); intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
intptr_t rb_val = get_register(rb); 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) { if (opcode == LHZUX) {
DCHECK(ra != 0 && ra != rt); DCHECK(ra != 0 && ra != rt);
set_register(ra, ra_val + rb_val); set_register(ra, ra_val + rb_val);
...@@ -3090,7 +2870,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) { ...@@ -3090,7 +2870,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
int rb = instr->RBValue(); int rb = instr->RBValue();
intptr_t ra_val = ra == 0 ? 0 : get_register(ra); intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
intptr_t rb_val = get_register(rb); 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; break;
} }
case LBARX: { case LBARX: {
...@@ -3108,7 +2888,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) { ...@@ -3108,7 +2888,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
int rb = instr->RBValue(); int rb = instr->RBValue();
intptr_t ra_val = ra == 0 ? 0 : get_register(ra); intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
intptr_t rb_val = get_register(rb); 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; break;
} }
case LWARX: { case LWARX: {
...@@ -3117,7 +2897,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) { ...@@ -3117,7 +2897,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
int rb = instr->RBValue(); int rb = instr->RBValue();
intptr_t ra_val = ra == 0 ? 0 : get_register(ra); intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
intptr_t rb_val = get_register(rb); 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; break;
} }
case LDARX: { case LDARX: {
...@@ -3126,7 +2906,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) { ...@@ -3126,7 +2906,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
int rb = instr->RBValue(); int rb = instr->RBValue();
intptr_t ra_val = ra == 0 ? 0 : get_register(ra); intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
intptr_t rb_val = get_register(rb); 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; break;
} }
case DCBF: { case DCBF: {
...@@ -3167,7 +2947,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) { ...@@ -3167,7 +2947,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
int rt = instr->RTValue(); int rt = instr->RTValue();
intptr_t ra_val = ra == 0 ? 0 : get_register(ra); intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
int offset = SIGN_EXT_IMM16(instr->Bits(15, 0)); 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); set_register(rt, result);
if (opcode == LHZU) { if (opcode == LHZU) {
set_register(ra, ra_val + offset); set_register(ra, ra_val + offset);
...@@ -3181,7 +2961,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) { ...@@ -3181,7 +2961,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
int rt = instr->RTValue(); int rt = instr->RTValue();
intptr_t ra_val = ra == 0 ? 0 : get_register(ra); intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
int offset = SIGN_EXT_IMM16(instr->Bits(15, 0)); 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); set_register(rt, result);
if (opcode == LHAU) { if (opcode == LHAU) {
set_register(ra, ra_val + offset); set_register(ra, ra_val + offset);
...@@ -3196,7 +2976,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) { ...@@ -3196,7 +2976,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
intptr_t ra_val = ra == 0 ? 0 : get_register(ra); intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
int16_t rs_val = get_register(rs); int16_t rs_val = get_register(rs);
int offset = SIGN_EXT_IMM16(instr->Bits(15, 0)); 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) { if (opcode == STHU) {
DCHECK_NE(ra, 0); DCHECK_NE(ra, 0);
set_register(ra, ra_val + offset); set_register(ra, ra_val + offset);
...@@ -3216,7 +2996,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) { ...@@ -3216,7 +2996,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
int ra = instr->RAValue(); int ra = instr->RAValue();
int32_t offset = SIGN_EXT_IMM16(instr->Bits(15, 0)); int32_t offset = SIGN_EXT_IMM16(instr->Bits(15, 0));
intptr_t ra_val = ra == 0 ? 0 : get_register(ra); 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); float* fptr = reinterpret_cast<float*>(&val);
#if V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64 #if V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64
// Conversion using double changes sNan to qNan on ia32/x64 // Conversion using double changes sNan to qNan on ia32/x64
...@@ -3244,8 +3024,8 @@ void Simulator::ExecuteGeneric(Instruction* instr) { ...@@ -3244,8 +3024,8 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
int ra = instr->RAValue(); int ra = instr->RAValue();
int32_t offset = SIGN_EXT_IMM16(instr->Bits(15, 0)); int32_t offset = SIGN_EXT_IMM16(instr->Bits(15, 0));
intptr_t ra_val = ra == 0 ? 0 : get_register(ra); intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
int64_t* dptr = reinterpret_cast<int64_t*>(ReadDW(ra_val + offset)); int64_t dptr = ReadDW(ra_val + offset);
set_d_register(frt, *dptr); set_d_register(frt, dptr);
if (opcode == LFDU) { if (opcode == LFDU) {
DCHECK_NE(ra, 0); DCHECK_NE(ra, 0);
set_register(ra, ra_val + offset); set_register(ra, ra_val + offset);
...@@ -3275,7 +3055,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) { ...@@ -3275,7 +3055,7 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
#else #else
p = reinterpret_cast<int32_t*>(&frs_val); p = reinterpret_cast<int32_t*>(&frs_val);
#endif #endif
WriteW(ra_val + offset, *p, instr); WriteW(ra_val + offset, *p);
if (opcode == STFSU) { if (opcode == STFSU) {
DCHECK_NE(ra, 0); DCHECK_NE(ra, 0);
set_register(ra, ra_val + offset); set_register(ra, ra_val + offset);
...@@ -3849,19 +3629,19 @@ void Simulator::ExecuteGeneric(Instruction* instr) { ...@@ -3849,19 +3629,19 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
int offset = SIGN_EXT_IMM16(instr->Bits(15, 0) & ~3); int offset = SIGN_EXT_IMM16(instr->Bits(15, 0) & ~3);
switch (instr->Bits(1, 0)) { switch (instr->Bits(1, 0)) {
case 0: { // ld case 0: { // ld
intptr_t* result = ReadDW(ra_val + offset); intptr_t result = ReadDW(ra_val + offset);
set_register(rt, *result); set_register(rt, result);
break; break;
} }
case 1: { // ldu case 1: { // ldu
intptr_t* result = ReadDW(ra_val + offset); intptr_t result = ReadDW(ra_val + offset);
set_register(rt, *result); set_register(rt, result);
DCHECK_NE(ra, 0); DCHECK_NE(ra, 0);
set_register(ra, ra_val + offset); set_register(ra, ra_val + offset);
break; break;
} }
case 2: { // lwa case 2: { // lwa
intptr_t result = ReadW(ra_val + offset, instr); intptr_t result = ReadW(ra_val + offset);
set_register(rt, result); set_register(rt, result);
break; break;
} }
...@@ -4189,170 +3969,65 @@ uintptr_t Simulator::PopAddress() { ...@@ -4189,170 +3969,65 @@ uintptr_t Simulator::PopAddress() {
return address; return address;
} }
Simulator::LocalMonitor::LocalMonitor() Simulator::GlobalMonitor::GlobalMonitor()
: access_state_(MonitorAccess::Open), : access_state_(MonitorAccess::Open),
tagged_addr_(0), 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; access_state_ = MonitorAccess::Open;
tagged_addr_ = 0; tagged_addr_ = 0;
size_ = TransactionSize::None; size_ = TransactionSize::None;
thread_id_ = ThreadId::Invalid();
} }
void Simulator::LocalMonitor::NotifyLoad(int32_t addr) { void Simulator::GlobalMonitor::NotifyLoadExcl(uintptr_t addr,
if (access_state_ == MonitorAccess::Exclusive) { TransactionSize size,
// A load could cause a cache eviction which will affect the monitor. As a ThreadId thread_id) {
// result, it's most strict to unconditionally clear the local monitor on // TODO(s390): By using Global Monitors, we are effectively limiting one
// load. // active reservation across all processors. This would potentially serialize
Clear(); // 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.
void Simulator::LocalMonitor::NotifyLoadExcl(int32_t addr,
TransactionSize size) {
access_state_ = MonitorAccess::Exclusive; access_state_ = MonitorAccess::Exclusive;
tagged_addr_ = addr; tagged_addr_ = addr;
size_ = size; size_ = size;
thread_id_ = thread_id;
} }
void Simulator::LocalMonitor::NotifyStore(int32_t addr) { void Simulator::GlobalMonitor::NotifyStore(uintptr_t addr, TransactionSize size,
if (access_state_ == MonitorAccess::Exclusive) { ThreadId thread_id) {
// 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) {
if (access_state_ == MonitorAccess::Exclusive) { 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(); 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( bool Simulator::GlobalMonitor::NotifyStoreExcl(uintptr_t addr,
int32_t addr, bool is_requesting_processor) { TransactionSize size,
if (access_state_ == MonitorAccess::Exclusive) { ThreadId thread_id) {
if (is_requesting_processor) { bool permission = access_state_ == MonitorAccess::Exclusive &&
if (addr == tagged_addr_) { addr == tagged_addr_ && size_ == size &&
Clear_Locked(); thread_id_.Equals(thread_id);
return true; // The reservation is cleared if the processor holding the reservation
} // executes a store conditional instruction to any address.
} else if (addr == tagged_addr_) { Clear();
Clear_Locked(); return permission;
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;
} }
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
#undef SScanF
#endif // USE_SIMULATOR #endif // USE_SIMULATOR
#endif // V8_TARGET_ARCH_PPC #endif // V8_TARGET_ARCH_PPC
...@@ -13,6 +13,8 @@ ...@@ -13,6 +13,8 @@
#define V8_PPC_SIMULATOR_PPC_H_ #define V8_PPC_SIMULATOR_PPC_H_
#include "src/allocation.h" #include "src/allocation.h"
#include "src/base/lazy-instance.h"
#include "src/base/platform/mutex.h"
#if defined(USE_SIMULATOR) #if defined(USE_SIMULATOR)
// Running with a simulator. // Running with a simulator.
...@@ -241,49 +243,61 @@ class Simulator : public SimulatorBase { ...@@ -241,49 +243,61 @@ class Simulator : public SimulatorBase {
void PrintStopInfo(uint32_t code); void PrintStopInfo(uint32_t code);
// Read and write memory. // Read and write memory.
inline uint8_t ReadBU(intptr_t addr); template <typename T>
inline uint8_t ReadExBU(intptr_t addr); inline void Read(uintptr_t address, T* value) {
inline int8_t ReadB(intptr_t addr); base::MutexGuard lock_guard(&global_monitor_.Pointer()->mutex);
inline void WriteB(intptr_t addr, uint8_t value); memcpy(value, reinterpret_cast<const char*>(address), sizeof(T));
inline int WriteExB(intptr_t addr, uint8_t value); }
inline void WriteB(intptr_t addr, int8_t value);
template <typename T>
inline uint16_t ReadHU(intptr_t addr, Instruction* instr); inline void ReadEx(uintptr_t address, T* value) {
inline uint16_t ReadExHU(intptr_t addr, Instruction* instr); base::MutexGuard lock_guard(&global_monitor_.Pointer()->mutex);
inline int16_t ReadH(intptr_t addr, Instruction* instr); global_monitor_.Pointer()->NotifyLoadExcl(
// Note: Overloaded on the sign of the value. address, static_cast<TransactionSize>(sizeof(T)),
inline void WriteH(intptr_t addr, uint16_t value, Instruction* instr); isolate_->thread_id());
inline int WriteExH(intptr_t addr, uint16_t value, Instruction* instr); memcpy(value, reinterpret_cast<const char*>(address), sizeof(T));
inline void WriteH(intptr_t addr, int16_t value, Instruction* instr); }
inline uint32_t ReadWU(intptr_t addr, Instruction* instr); template <typename T>
inline uint32_t ReadExWU(intptr_t addr, Instruction* instr); inline void Write(uintptr_t address, T value) {
inline int32_t ReadW(intptr_t addr, Instruction* instr); base::MutexGuard lock_guard(&global_monitor_.Pointer()->mutex);
inline void WriteW(intptr_t addr, uint32_t value, Instruction* instr); global_monitor_.Pointer()->NotifyStore(
inline int WriteExW(intptr_t addr, uint32_t value, Instruction* instr); address, static_cast<TransactionSize>(sizeof(T)),
inline void WriteW(intptr_t addr, int32_t value, Instruction* instr); isolate_->thread_id());
memcpy(reinterpret_cast<char*>(address), &value, sizeof(T));
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); template <typename T>
inline uint64_t ReadExDWU(intptr_t addr, Instruction* instr); 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 Trace(Instruction* instr);
void SetCR0(intptr_t result, bool setSO = false); void SetCR0(intptr_t result, bool setSO = false);
void ExecuteBranchConditional(Instruction* instr, BCType type); 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 ExecuteGeneric(Instruction* instr);
void SetFPSCR(int bit) { fp_condition_reg_ |= (1 << (31 - bit)); } void SetFPSCR(int bit) { fp_condition_reg_ |= (1 << (31 - bit)); }
...@@ -364,71 +378,31 @@ class Simulator : public SimulatorBase { ...@@ -364,71 +378,31 @@ class Simulator : public SimulatorBase {
Byte = 1, Byte = 1,
HalfWord = 2, HalfWord = 2,
Word = 4, Word = 4,
}; DWord = 8,
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 { class GlobalMonitor {
public: public:
GlobalMonitor(); 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*. // Exposed so it can be accessed by Simulator::{Read,Write}Ex*.
base::Mutex mutex; base::Mutex mutex;
void NotifyLoadExcl_Locked(int32_t addr, Processor* processor); void NotifyLoadExcl(uintptr_t addr, TransactionSize size,
void NotifyStore_Locked(int32_t addr, Processor* processor); ThreadId thread_id);
bool NotifyStoreExcl_Locked(int32_t addr, Processor* processor); void NotifyStore(uintptr_t addr, TransactionSize size, ThreadId thread_id);
bool NotifyStoreExcl(uintptr_t addr, TransactionSize size,
// Called when the simulator is destroyed. ThreadId thread_id);
void RemoveProcessor(Processor* processor);
private: private:
bool IsProcessorInLinkedList_Locked(Processor* processor) const; void Clear();
void PrependProcessor_Locked(Processor* processor);
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_; 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