mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-17 22:32:51 +00:00
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:
parent
b9354f830a
commit
9b260640e7
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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_) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user