Bug 1436955 - ARM64 Simulator, bugfixes and wasm support. r=bbouvier

- fix a bug where the wrong register was picked up
- support wasm out-of-bounds traps
- support wasm illegal instruction traps
- support (float,float)->float callout signature
- support wait() and wake() callout signatures

--HG--
extra : rebase_source : 9ec124e9e629da245360a80a4a6974d71c9a87c8
extra : source : ba2afb5aa6915b1112d0f58ab653949bec8d07fc
This commit is contained in:
Lars T Hansen 2018-01-30 01:38:26 +01:00
parent b9354f830a
commit 9b260640e7
3 changed files with 232 additions and 87 deletions

View File

@ -33,15 +33,16 @@
#include "threading/LockGuard.h"
#include "vm/Runtime.h"
#include "wasm/WasmInstance.h"
#include "wasm/WasmProcess.h"
#include "wasm/WasmSignalHandlers.h"
js::jit::SimulatorProcess* js::jit::SimulatorProcess::singleton_ = nullptr;
namespace vixl {
using mozilla::DebugOnly;
using js::jit::ABIFunctionType;
using js::jit::JitActivation;
using js::jit::SimulatorProcess;
Simulator::Simulator(JSContext* cx, Decoder* decoder, FILE* stream)
@ -218,13 +219,13 @@ uintptr_t* Simulator::addressOfStackLimit() {
bool Simulator::overRecursed(uintptr_t newsp) const {
if (newsp)
newsp = xreg(31, Reg31IsStackPointer);
newsp = get_sp();
return newsp <= stackLimit();
}
bool Simulator::overRecursedWithExtra(uint32_t extra) const {
uintptr_t newsp = xreg(31, Reg31IsStackPointer) - extra;
uintptr_t newsp = get_sp() - extra;
return newsp <= stackLimit();
}
@ -235,31 +236,91 @@ void Simulator::trigger_wasm_interrupt() {
}
static inline JitActivation*
GetJitActivation(JSContext* cx)
{
if (!js::wasm::CodeExists)
return nullptr;
if (!cx->activation() || !cx->activation()->isJit())
return nullptr;
return cx->activation()->asJit();
}
JS::ProfilingFrameIterator::RegisterState
Simulator::registerState()
{
JS::ProfilingFrameIterator::RegisterState state;
state.pc = (uint8_t*) get_pc();
state.fp = (uint8_t*) get_fp();
state.lr = (uint8_t*) get_lr();
state.sp = (uint8_t*) get_sp();
return state;
}
// The signal handler only redirects the PC to the interrupt stub when the PC is
// in function code. However, this guard is racy for the ARM simulator since the
// signal handler samples PC in the middle of simulating an instruction and thus
// the current PC may have advanced once since the signal handler's guard. So we
// re-check here.
void Simulator::handle_wasm_interrupt() {
void Simulator::handle_wasm_interrupt()
{
if (!js::wasm::CodeExists)
return;
uint8_t* pc = (uint8_t*)get_pc();
uint8_t* fp = (uint8_t*)xreg(30);
const js::wasm::ModuleSegment* ms = nullptr;
if (!js::wasm::InInterruptibleCode(cx_, pc, &ms))
return;
JS::ProfilingFrameIterator::RegisterState state;
state.pc = pc;
state.fp = fp;
state.lr = (uint8_t*) xreg(30);
state.sp = (uint8_t*) xreg(31);
JitActivation* act = GetJitActivation(cx_);
if (!act)
return;
if (!cx_->activation_->asJit()->startWasmInterrupt(state))
if (!act->startWasmInterrupt(registerState()))
return;
set_pc((Instruction*)ms->interruptCode());
}
bool
Simulator::handle_wasm_seg_fault(uintptr_t addr, unsigned numBytes)
{
JitActivation* act = GetJitActivation(cx_);
if (!act)
return false;
uint8_t* pc = (uint8_t*)get_pc();
uint8_t* fp = (uint8_t*)get_fp();
const js::wasm::CodeSegment* segment = js::wasm::LookupCodeSegment(pc);
if (!segment)
return false;
const js::wasm::ModuleSegment* moduleSegment = segment->asModule();
js::wasm::Instance* instance = js::wasm::LookupFaultingInstance(*moduleSegment, pc, fp);
if (!instance)
return false;
MOZ_RELEASE_ASSERT(&instance->code() == &moduleSegment->code());
if (!instance->memoryAccessInGuardRegion((uint8_t*)addr, numBytes))
return false;
const js::wasm::MemoryAccess* memoryAccess = instance->code().lookupMemoryAccess(pc);
if (!memoryAccess) {
if (!act->startWasmInterrupt(registerState()))
MOZ_CRASH("Cannot start interrupt");
if (!instance->code().containsCodePC(pc))
MOZ_CRASH("Cannot map PC to trap handler");
set_pc((Instruction*)moduleSegment->outOfBoundsCode());
return true;
}
MOZ_ASSERT(memoryAccess->hasTrapOutOfLineCode());
set_pc((Instruction*)memoryAccess->trapOutOfLineCode(moduleSegment->base()));
return true;
}
int64_t Simulator::call(uint8_t* entry, int argument_count, ...) {
va_list parameters;
@ -303,12 +364,12 @@ int64_t Simulator::call(uint8_t* entry, int argument_count, ...) {
va_end(parameters);
// Call must transition back to native code on exit.
VIXL_ASSERT(xreg(30) == int64_t(kEndOfSimAddress));
VIXL_ASSERT(get_lr() == int64_t(kEndOfSimAddress));
// Execute the simulation.
DebugOnly<int64_t> entryStack = xreg(31, Reg31IsStackPointer);
DebugOnly<int64_t> entryStack = get_sp();
RunFrom((Instruction*)entry);
DebugOnly<int64_t> exitStack = xreg(31, Reg31IsStackPointer);
DebugOnly<int64_t> exitStack = get_sp();
VIXL_ASSERT(entryStack == exitStack);
int64_t result = xreg(0);
@ -403,6 +464,29 @@ void* Simulator::RedirectNativeFunction(void* nativeFunction, ABIFunctionType ty
return redirection->addressOfSvcInstruction();
}
bool
Simulator::handle_wasm_ill_fault()
{
JitActivation* act = GetJitActivation(cx_);
if (!act)
return false;
uint8_t* pc = (uint8_t*)get_pc();
const js::wasm::CodeSegment* segment = js::wasm::LookupCodeSegment(pc);
if (!segment || !segment->isModule())
return false;
const js::wasm::ModuleSegment* moduleSegment = segment->asModule();
js::wasm::Trap trap;
js::wasm::BytecodeOffset bytecode;
if (!moduleSegment->code().lookupTrap(pc, &trap, &bytecode))
return false;
act->startWasmTrap(trap, bytecode.offset, registerState());
set_pc((Instruction*)moduleSegment->trapCode());
return true;
}
void Simulator::VisitException(const Instruction* instr) {
switch (instr->Mask(ExceptionMask)) {
@ -415,7 +499,8 @@ void Simulator::VisitException(const Instruction* instr) {
case HLT:
switch (instr->ImmException()) {
case kUnreachableOpcode:
DoUnreachable(instr);
if (!handle_wasm_ill_fault())
DoUnreachable(instr);
return;
case kTraceOpcode:
DoTrace(instr);
@ -439,12 +524,12 @@ void Simulator::VisitException(const Instruction* instr) {
return;
case kMarkStackPointer: {
js::AutoEnterOOMUnsafeRegion oomUnsafe;
if (!spStack_.append(xreg(31, Reg31IsStackPointer)))
if (!spStack_.append(get_sp()))
oomUnsafe.crash("tracking stack for ARM64 simulator");
return;
}
case kCheckStackPointer: {
int64_t current = xreg(31, Reg31IsStackPointer);
int64_t current = get_sp();
int64_t expected = spStack_.popCopy();
VIXL_ASSERT(current == expected);
return;
@ -492,6 +577,10 @@ typedef int64_t (*Prototype_General7)(int64_t arg0, int64_t arg1, int64_t arg2,
int64_t arg4, int64_t arg5, int64_t arg6);
typedef int64_t (*Prototype_General8)(int64_t arg0, int64_t arg1, int64_t arg2, int64_t arg3,
int64_t arg4, int64_t arg5, int64_t arg6, int64_t arg7);
typedef int64_t (*Prototype_GeneralGeneralGeneralInt64)(int64_t arg0, int32_t arg1, int32_t arg2,
int64_t arg3);
typedef int64_t (*Prototype_GeneralGeneralInt64Int64)(int64_t arg0, int32_t arg1, int64_t arg2,
int64_t arg3);
typedef int64_t (*Prototype_Int_Double)(double arg0);
typedef int64_t (*Prototype_Int_IntDouble)(int32_t arg0, double arg1);
@ -500,6 +589,7 @@ typedef int64_t (*Prototype_Int_IntDoubleIntInt)(uint64_t arg0, double arg1,
uint64_t arg2, uint64_t arg3);
typedef float (*Prototype_Float32_Float32)(float arg0);
typedef float (*Prototype_Float32_Float32Float32)(float arg0, float arg1);
typedef double (*Prototype_Double_None)();
typedef double (*Prototype_Double_Double)(double arg0);
@ -538,7 +628,7 @@ Simulator::VisitCallRedirection(const Instruction* instr)
DebugOnly<int64_t> x27 = xreg(27);
DebugOnly<int64_t> x28 = xreg(28);
DebugOnly<int64_t> x29 = xreg(29);
DebugOnly<int64_t> savedSP = xreg(31, Reg31IsStackPointer);
DebugOnly<int64_t> savedSP = get_sp();
// Remember LR for returning from the "call".
int64_t savedLR = xreg(30);
@ -561,6 +651,7 @@ Simulator::VisitCallRedirection(const Instruction* instr)
double d2 = dreg(2);
double d3 = dreg(3);
float s0 = sreg(0);
float s1 = sreg(1);
// Dispatch the call and set the return value.
switch (redir->type()) {
@ -610,6 +701,16 @@ Simulator::VisitCallRedirection(const Instruction* instr)
setGPR64Result(ret);
break;
}
case js::jit::Args_Int_GeneralGeneralGeneralInt64: {
int64_t ret = reinterpret_cast<Prototype_GeneralGeneralGeneralInt64>(nativeFn)(x0, x1, x2, x3);
setGPR64Result(ret);
break;
}
case js::jit::Args_Int_GeneralGeneralInt64Int64: {
int64_t ret = reinterpret_cast<Prototype_GeneralGeneralInt64Int64>(nativeFn)(x0, x1, x2, x3);
setGPR64Result(ret);
break;
}
// Cases with GPR return type. This can be int32 or int64, but int64 is a safer assumption.
case js::jit::Args_Int_Double: {
@ -641,6 +742,11 @@ Simulator::VisitCallRedirection(const Instruction* instr)
setFP32Result(ret);
break;
}
case js::jit::Args_Float32_Float32Float32: {
float ret = reinterpret_cast<Prototype_Float32_Float32Float32>(nativeFn)(s0, s1);
setFP32Result(ret);
break;
}
// Cases with double return type.
case js::jit::Args_Double_None: {
@ -705,7 +811,7 @@ Simulator::VisitCallRedirection(const Instruction* instr)
VIXL_ASSERT(xreg(29) == x29);
// Assert that the stack is unchanged.
VIXL_ASSERT(savedSP == xreg(31, Reg31IsStackPointer));
VIXL_ASSERT(savedSP == get_sp());
// Simulate a return.
set_lr(savedLR);

View File

@ -1012,7 +1012,38 @@ void Simulator::VisitLoadStoreRegisterOffset(const Instruction* instr) {
LoadStoreHelper(instr, offset, Offset);
}
template<typename T>
static T Faulted() {
return ~0;
}
template<>
Simulator::qreg_t Faulted() {
static_assert(kQRegSizeInBytes == 16, "Known constraint");
static Simulator::qreg_t dummy = { {
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255
} };
return dummy;
}
template<typename T> T
Simulator::Read(uintptr_t address)
{
address = Memory::AddressUntag(address);
if (handle_wasm_seg_fault(address, sizeof(T)))
return Faulted<T>();
return Memory::Read<T>(address);
}
template <typename T> void
Simulator::Write(uintptr_t address, T value)
{
address = Memory::AddressUntag(address);
if (handle_wasm_seg_fault(address, sizeof(T)))
return;
Memory::Write<T>(address, value);
}
void Simulator::LoadStoreHelper(const Instruction* instr,
int64_t offset,
@ -1023,43 +1054,43 @@ void Simulator::LoadStoreHelper(const Instruction* instr,
LoadStoreOp op = static_cast<LoadStoreOp>(instr->Mask(LoadStoreMask));
switch (op) {
case LDRB_w:
set_wreg(srcdst, Memory::Read<uint8_t>(address), NoRegLog); break;
set_wreg(srcdst, Read<uint8_t>(address), NoRegLog); break;
case LDRH_w:
set_wreg(srcdst, Memory::Read<uint16_t>(address), NoRegLog); break;
set_wreg(srcdst, Read<uint16_t>(address), NoRegLog); break;
case LDR_w:
set_wreg(srcdst, Memory::Read<uint32_t>(address), NoRegLog); break;
set_wreg(srcdst, Read<uint32_t>(address), NoRegLog); break;
case LDR_x:
set_xreg(srcdst, Memory::Read<uint64_t>(address), NoRegLog); break;
set_xreg(srcdst, Read<uint64_t>(address), NoRegLog); break;
case LDRSB_w:
set_wreg(srcdst, Memory::Read<int8_t>(address), NoRegLog); break;
set_wreg(srcdst, Read<int8_t>(address), NoRegLog); break;
case LDRSH_w:
set_wreg(srcdst, Memory::Read<int16_t>(address), NoRegLog); break;
set_wreg(srcdst, Read<int16_t>(address), NoRegLog); break;
case LDRSB_x:
set_xreg(srcdst, Memory::Read<int8_t>(address), NoRegLog); break;
set_xreg(srcdst, Read<int8_t>(address), NoRegLog); break;
case LDRSH_x:
set_xreg(srcdst, Memory::Read<int16_t>(address), NoRegLog); break;
set_xreg(srcdst, Read<int16_t>(address), NoRegLog); break;
case LDRSW_x:
set_xreg(srcdst, Memory::Read<int32_t>(address), NoRegLog); break;
set_xreg(srcdst, Read<int32_t>(address), NoRegLog); break;
case LDR_b:
set_breg(srcdst, Memory::Read<uint8_t>(address), NoRegLog); break;
set_breg(srcdst, Read<uint8_t>(address), NoRegLog); break;
case LDR_h:
set_hreg(srcdst, Memory::Read<uint16_t>(address), NoRegLog); break;
set_hreg(srcdst, Read<uint16_t>(address), NoRegLog); break;
case LDR_s:
set_sreg(srcdst, Memory::Read<float>(address), NoRegLog); break;
set_sreg(srcdst, Read<float>(address), NoRegLog); break;
case LDR_d:
set_dreg(srcdst, Memory::Read<double>(address), NoRegLog); break;
set_dreg(srcdst, Read<double>(address), NoRegLog); break;
case LDR_q:
set_qreg(srcdst, Memory::Read<qreg_t>(address), NoRegLog); break;
set_qreg(srcdst, Read<qreg_t>(address), NoRegLog); break;
case STRB_w: Memory::Write<uint8_t>(address, wreg(srcdst)); break;
case STRH_w: Memory::Write<uint16_t>(address, wreg(srcdst)); break;
case STR_w: Memory::Write<uint32_t>(address, wreg(srcdst)); break;
case STR_x: Memory::Write<uint64_t>(address, xreg(srcdst)); break;
case STR_b: Memory::Write<uint8_t>(address, breg(srcdst)); break;
case STR_h: Memory::Write<uint16_t>(address, hreg(srcdst)); break;
case STR_s: Memory::Write<float>(address, sreg(srcdst)); break;
case STR_d: Memory::Write<double>(address, dreg(srcdst)); break;
case STR_q: Memory::Write<qreg_t>(address, qreg(srcdst)); break;
case STRB_w: Write<uint8_t>(address, wreg(srcdst)); break;
case STRH_w: Write<uint16_t>(address, wreg(srcdst)); break;
case STR_w: Write<uint32_t>(address, wreg(srcdst)); break;
case STR_x: Write<uint64_t>(address, xreg(srcdst)); break;
case STR_b: Write<uint8_t>(address, breg(srcdst)); break;
case STR_h: Write<uint16_t>(address, hreg(srcdst)); break;
case STR_s: Write<float>(address, sreg(srcdst)); break;
case STR_d: Write<double>(address, dreg(srcdst)); break;
case STR_q: Write<qreg_t>(address, qreg(srcdst)); break;
// Ignore prfm hint instructions.
case PRFM: break;
@ -1129,58 +1160,58 @@ void Simulator::LoadStorePairHelper(const Instruction* instr,
// Use NoRegLog to suppress the register trace (LOG_REGS, LOG_FP_REGS). We
// will print a more detailed log.
case LDP_w: {
set_wreg(rt, Memory::Read<uint32_t>(address), NoRegLog);
set_wreg(rt2, Memory::Read<uint32_t>(address2), NoRegLog);
set_wreg(rt, Read<uint32_t>(address), NoRegLog);
set_wreg(rt2, Read<uint32_t>(address2), NoRegLog);
break;
}
case LDP_s: {
set_sreg(rt, Memory::Read<float>(address), NoRegLog);
set_sreg(rt2, Memory::Read<float>(address2), NoRegLog);
set_sreg(rt, Read<float>(address), NoRegLog);
set_sreg(rt2, Read<float>(address2), NoRegLog);
break;
}
case LDP_x: {
set_xreg(rt, Memory::Read<uint64_t>(address), NoRegLog);
set_xreg(rt2, Memory::Read<uint64_t>(address2), NoRegLog);
set_xreg(rt, Read<uint64_t>(address), NoRegLog);
set_xreg(rt2, Read<uint64_t>(address2), NoRegLog);
break;
}
case LDP_d: {
set_dreg(rt, Memory::Read<double>(address), NoRegLog);
set_dreg(rt2, Memory::Read<double>(address2), NoRegLog);
set_dreg(rt, Read<double>(address), NoRegLog);
set_dreg(rt2, Read<double>(address2), NoRegLog);
break;
}
case LDP_q: {
set_qreg(rt, Memory::Read<qreg_t>(address), NoRegLog);
set_qreg(rt2, Memory::Read<qreg_t>(address2), NoRegLog);
set_qreg(rt, Read<qreg_t>(address), NoRegLog);
set_qreg(rt2, Read<qreg_t>(address2), NoRegLog);
break;
}
case LDPSW_x: {
set_xreg(rt, Memory::Read<int32_t>(address), NoRegLog);
set_xreg(rt2, Memory::Read<int32_t>(address2), NoRegLog);
set_xreg(rt, Read<int32_t>(address), NoRegLog);
set_xreg(rt2, Read<int32_t>(address2), NoRegLog);
break;
}
case STP_w: {
Memory::Write<uint32_t>(address, wreg(rt));
Memory::Write<uint32_t>(address2, wreg(rt2));
Write<uint32_t>(address, wreg(rt));
Write<uint32_t>(address2, wreg(rt2));
break;
}
case STP_s: {
Memory::Write<float>(address, sreg(rt));
Memory::Write<float>(address2, sreg(rt2));
Write<float>(address, sreg(rt));
Write<float>(address2, sreg(rt2));
break;
}
case STP_x: {
Memory::Write<uint64_t>(address, xreg(rt));
Memory::Write<uint64_t>(address2, xreg(rt2));
Write<uint64_t>(address, xreg(rt));
Write<uint64_t>(address2, xreg(rt2));
break;
}
case STP_d: {
Memory::Write<double>(address, dreg(rt));
Memory::Write<double>(address2, dreg(rt2));
Write<double>(address, dreg(rt));
Write<double>(address2, dreg(rt2));
break;
}
case STP_q: {
Memory::Write<qreg_t>(address, qreg(rt));
Memory::Write<qreg_t>(address2, qreg(rt2));
Write<qreg_t>(address, qreg(rt));
Write<qreg_t>(address2, qreg(rt2));
break;
}
default: VIXL_UNREACHABLE();
@ -1276,32 +1307,32 @@ void Simulator::VisitLoadStoreExclusive(const Instruction* instr) {
case LDXRB_w:
case LDAXRB_w:
case LDARB_w:
set_wreg(rt, Memory::Read<uint8_t>(address), NoRegLog);
set_wreg(rt, Read<uint8_t>(address), NoRegLog);
break;
case LDXRH_w:
case LDAXRH_w:
case LDARH_w:
set_wreg(rt, Memory::Read<uint16_t>(address), NoRegLog);
set_wreg(rt, Read<uint16_t>(address), NoRegLog);
break;
case LDXR_w:
case LDAXR_w:
case LDAR_w:
set_wreg(rt, Memory::Read<uint32_t>(address), NoRegLog);
set_wreg(rt, Read<uint32_t>(address), NoRegLog);
break;
case LDXR_x:
case LDAXR_x:
case LDAR_x:
set_xreg(rt, Memory::Read<uint64_t>(address), NoRegLog);
set_xreg(rt, Read<uint64_t>(address), NoRegLog);
break;
case LDXP_w:
case LDAXP_w:
set_wreg(rt, Memory::Read<uint32_t>(address), NoRegLog);
set_wreg(rt2, Memory::Read<uint32_t>(address + element_size), NoRegLog);
set_wreg(rt, Read<uint32_t>(address), NoRegLog);
set_wreg(rt2, Read<uint32_t>(address + element_size), NoRegLog);
break;
case LDXP_x:
case LDAXP_x:
set_xreg(rt, Memory::Read<uint64_t>(address), NoRegLog);
set_xreg(rt2, Memory::Read<uint64_t>(address + element_size), NoRegLog);
set_xreg(rt, Read<uint64_t>(address), NoRegLog);
set_xreg(rt2, Read<uint64_t>(address + element_size), NoRegLog);
break;
default:
VIXL_UNREACHABLE();
@ -1341,32 +1372,32 @@ void Simulator::VisitLoadStoreExclusive(const Instruction* instr) {
case STXRB_w:
case STLXRB_w:
case STLRB_w:
Memory::Write<uint8_t>(address, wreg(rt));
Write<uint8_t>(address, wreg(rt));
break;
case STXRH_w:
case STLXRH_w:
case STLRH_w:
Memory::Write<uint16_t>(address, wreg(rt));
Write<uint16_t>(address, wreg(rt));
break;
case STXR_w:
case STLXR_w:
case STLR_w:
Memory::Write<uint32_t>(address, wreg(rt));
Write<uint32_t>(address, wreg(rt));
break;
case STXR_x:
case STLXR_x:
case STLR_x:
Memory::Write<uint64_t>(address, xreg(rt));
Write<uint64_t>(address, xreg(rt));
break;
case STXP_w:
case STLXP_w:
Memory::Write<uint32_t>(address, wreg(rt));
Memory::Write<uint32_t>(address + element_size, wreg(rt2));
Write<uint32_t>(address, wreg(rt));
Write<uint32_t>(address + element_size, wreg(rt2));
break;
case STXP_x:
case STLXP_x:
Memory::Write<uint64_t>(address, xreg(rt));
Memory::Write<uint64_t>(address + element_size, xreg(rt2));
Write<uint64_t>(address, xreg(rt));
Write<uint64_t>(address + element_size, xreg(rt2));
break;
default:
VIXL_UNREACHABLE();
@ -1393,27 +1424,27 @@ void Simulator::VisitLoadLiteral(const Instruction* instr) {
// Use NoRegLog to suppress the register trace (LOG_REGS, LOG_VREGS), then
// print a more detailed log.
case LDR_w_lit:
set_wreg(rt, Memory::Read<uint32_t>(address), NoRegLog);
set_wreg(rt, Read<uint32_t>(address), NoRegLog);
LogRead(address, rt, kPrintWReg);
break;
case LDR_x_lit:
set_xreg(rt, Memory::Read<uint64_t>(address), NoRegLog);
set_xreg(rt, Read<uint64_t>(address), NoRegLog);
LogRead(address, rt, kPrintXReg);
break;
case LDR_s_lit:
set_sreg(rt, Memory::Read<float>(address), NoRegLog);
set_sreg(rt, Read<float>(address), NoRegLog);
LogVRead(address, rt, kPrintSReg);
break;
case LDR_d_lit:
set_dreg(rt, Memory::Read<double>(address), NoRegLog);
set_dreg(rt, Read<double>(address), NoRegLog);
LogVRead(address, rt, kPrintDReg);
break;
case LDR_q_lit:
set_qreg(rt, Memory::Read<qreg_t>(address), NoRegLog);
set_qreg(rt, Read<qreg_t>(address), NoRegLog);
LogVRead(address, rt, kPrintReg1Q);
break;
case LDRSW_x_lit:
set_xreg(rt, Memory::Read<int32_t>(address), NoRegLog);
set_xreg(rt, Read<int32_t>(address), NoRegLog);
LogRead(address, rt, kPrintWReg);
break;
@ -2242,7 +2273,7 @@ void Simulator::SysOp_W(int op, int64_t val) {
case CIVAC: {
// Perform a dummy memory access to ensure that we have read access
// to the specified address.
volatile uint8_t y = Memory::Read<uint8_t>(val);
volatile uint8_t y = Read<uint8_t>(val);
USE(y);
// TODO: Implement "case ZVA:".
break;

View File

@ -721,6 +721,9 @@ class Simulator : public DecoderVisitor {
static bool supportsAtomics() {
return true;
}
template<typename T> T Read(uintptr_t address);
template <typename T> void Write(uintptr_t address_, T value);
JS::ProfilingFrameIterator::RegisterState registerState();
void ResetState();
@ -731,6 +734,9 @@ class Simulator : public DecoderVisitor {
// Simulation helpers.
const Instruction* pc() const { return pc_; }
const Instruction* get_pc() const { return pc_; }
int64_t get_sp() const { return xreg(31, Reg31IsStackPointer); }
int64_t get_lr() const { return xreg(30); }
int64_t get_fp() const { return xreg(29); }
template <typename T>
T get_pc_as() const { return reinterpret_cast<T>(const_cast<Instruction*>(pc())); }
@ -742,6 +748,8 @@ class Simulator : public DecoderVisitor {
void trigger_wasm_interrupt();
void handle_wasm_interrupt();
bool handle_wasm_ill_fault();
bool handle_wasm_seg_fault(uintptr_t addr, unsigned numBytes);
void increment_pc() {
if (!pc_modified_) {