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: Joran Siu <joransiu@ca.ibm.com> Cr-Commit-Position: refs/heads/master@{#57187}
This commit is contained in:
parent
9bd6e601cb
commit
6525976b1f
@ -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;
|
||||
#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); \
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
void Simulator::GlobalMonitor::NotifyStore(uintptr_t addr, TransactionSize size,
|
||||
ThreadId thread_id) {
|
||||
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) {
|
||||
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);
|
||||
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));
|
||||
}
|
||||
|
||||
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);
|
||||
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));
|
||||
}
|
||||
|
||||
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);
|
||||
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));
|
||||
}
|
||||
|
||||
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 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_;
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user