1335068 - Wasm: Split the global allocation out of the CodeSegment

1335068 - Break wasm globals out of the code segment.
This commit is contained in:
win7-7 2025-12-30 06:22:08 +02:00 committed by wuggy
commit 76d0a10fee
42 changed files with 352 additions and 632 deletions

View file

@ -4244,20 +4244,22 @@ LIRGenerator::visitWasmBoundsCheck(MWasmBoundsCheck* ins)
void
LIRGenerator::visitWasmLoadGlobalVar(MWasmLoadGlobalVar* ins)
{
LAllocation tlsPtr = useRegisterAtStart(ins->tlsPtr());
if (ins->type() == MIRType::Int64)
defineInt64(new(alloc()) LWasmLoadGlobalVarI64, ins);
defineInt64(new(alloc()) LWasmLoadGlobalVarI64(tlsPtr), ins);
else
define(new(alloc()) LWasmLoadGlobalVar, ins);
define(new(alloc()) LWasmLoadGlobalVar(tlsPtr), ins);
}
void
LIRGenerator::visitWasmStoreGlobalVar(MWasmStoreGlobalVar* ins)
{
MDefinition* value = ins->value();
LAllocation tlsPtr = useRegisterAtStart(ins->tlsPtr());
if (value->type() == MIRType::Int64)
add(new(alloc()) LWasmStoreGlobalVarI64(useInt64RegisterAtStart(value)), ins);
add(new(alloc()) LWasmStoreGlobalVarI64(useInt64RegisterAtStart(value), tlsPtr), ins);
else
add(new(alloc()) LWasmStoreGlobalVar(useRegisterAtStart(value)), ins);
add(new(alloc()) LWasmStoreGlobalVar(useRegisterAtStart(value), tlsPtr), ins);
}
void

View file

@ -12860,10 +12860,13 @@ class MAsmJSAtomicBinopHeap
}
};
class MWasmLoadGlobalVar : public MNullaryInstruction
class MWasmLoadGlobalVar
: public MUnaryInstruction,
public NoTypePolicy::Data
{
MWasmLoadGlobalVar(MIRType type, unsigned globalDataOffset, bool isConstant)
: globalDataOffset_(globalDataOffset), isConstant_(isConstant)
MWasmLoadGlobalVar(MIRType type, unsigned globalDataOffset, bool isConstant, MDefinition* tlsPtr)
: MUnaryInstruction(classOpcode, tlsPtr),
globalDataOffset_(globalDataOffset), isConstant_(isConstant)
{
MOZ_ASSERT(IsNumberType(type));
setResultType(type);
@ -12876,6 +12879,7 @@ class MWasmLoadGlobalVar : public MNullaryInstruction
public:
INSTRUCTION_HEADER(WasmLoadGlobalVar)
TRIVIAL_NEW_WRAPPERS
NAMED_OPERANDS((0, tlsPtr))
unsigned globalDataOffset() const { return globalDataOffset_; }
@ -12891,21 +12895,22 @@ class MWasmLoadGlobalVar : public MNullaryInstruction
};
class MWasmStoreGlobalVar
: public MUnaryInstruction,
: public MBinaryInstruction,
public NoTypePolicy::Data
{
MWasmStoreGlobalVar(unsigned globalDataOffset, MDefinition* v)
: MUnaryInstruction(v), globalDataOffset_(globalDataOffset)
{}
MWasmStoreGlobalVar(unsigned globalDataOffset, MDefinition* value, MDefinition* tlsPtr)
: MBinaryInstruction(classOpcode, value, tlsPtr),
globalDataOffset_(globalDataOffset)
{ }
unsigned globalDataOffset_;
public:
INSTRUCTION_HEADER(WasmStoreGlobalVar)
TRIVIAL_NEW_WRAPPERS
NAMED_OPERANDS((0, value), (1, tlsPtr))
unsigned globalDataOffset() const { return globalDataOffset_; }
MDefinition* value() const { return getOperand(0); }
AliasSet getAliasSet() const override {
return AliasSet::Store(AliasSet::WasmGlobalVar);

View file

@ -280,16 +280,12 @@ class RegisterAllocator
allRegisters_(RegisterSet::All())
{
if (mir->compilingWasm()) {
#if defined(JS_CODEGEN_X64)
#if defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_ARM) || \
defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
allRegisters_.take(AnyRegister(HeapReg));
#elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32) || \
defined(JS_CODEGEN_MIPS64) || defined(JS_CODEGEN_LOONGARCH64)
allRegisters_.take(AnyRegister(HeapReg));
allRegisters_.take(AnyRegister(GlobalReg));
#elif defined(JS_CODEGEN_ARM64)
allRegisters_.take(AnyRegister(HeapReg));
allRegisters_.take(AnyRegister(HeapLenReg));
allRegisters_.take(AnyRegister(GlobalReg));
#endif
} else {
if (FramePointer != InvalidReg && mir->instrumentedProfiling())

View file

@ -72,7 +72,6 @@ static constexpr Register IntArgReg0 = r0;
static constexpr Register IntArgReg1 = r1;
static constexpr Register IntArgReg2 = r2;
static constexpr Register IntArgReg3 = r3;
static constexpr Register GlobalReg = r10;
static constexpr Register HeapReg = r11;
static constexpr Register CallTempNonArgRegs[] = { r5, r6, r7, r8 };
static const uint32_t NumCallTempNonArgRegs =
@ -159,11 +158,6 @@ struct ScratchDoubleScope : public AutoFloatRegisterScope
{ }
};
// A bias applied to the GlobalReg to allow the use of instructions with small
// negative immediate offsets which doubles the range of global data that can be
// accessed with a single instruction.
static const int32_t WasmGlobalRegBias = 1024;
// Registers used in the GenerateFFIIonExit Enable Activation block.
static constexpr Register WasmIonExitRegCallee = r4;
static constexpr Register WasmIonExitRegE0 = r0;

View file

@ -2336,9 +2336,10 @@ CodeGeneratorARM::visitAsmJSLoadHeap(LAsmJSLoadHeap* ins)
BufferOffset cmp = masm.as_cmp(ptrReg, Imm8(0));
masm.append(wasm::BoundsCheck(cmp.getOffset()));
size_t nanOffset = size == 32 ? wasm::NaN32GlobalDataOffset : wasm::NaN64GlobalDataOffset;
masm.ma_vldr(Address(GlobalReg, nanOffset - WasmGlobalRegBias), output, scratch,
Assembler::AboveOrEqual);
if (size == 32)
masm.ma_vimm_f32(GenericNaN(), output, Assembler::AboveOrEqual);
else
masm.ma_vimm(GenericNaN(), output, Assembler::AboveOrEqual);
cond = Assembler::Below;
}
@ -2924,71 +2925,6 @@ CodeGeneratorARM::visitEffectiveAddress(LEffectiveAddress* ins)
masm.ma_add(Imm32(mir->displacement()), output, scratch);
}
void
CodeGeneratorARM::visitWasmLoadGlobalVar(LWasmLoadGlobalVar* ins)
{
const MWasmLoadGlobalVar* mir = ins->mir();
unsigned addr = mir->globalDataOffset() - WasmGlobalRegBias;
ScratchRegisterScope scratch(masm);
if (mir->type() == MIRType::Int32) {
masm.ma_dtr(IsLoad, GlobalReg, Imm32(addr), ToRegister(ins->output()), scratch);
} else if (mir->type() == MIRType::Float32) {
VFPRegister vd(ToFloatRegister(ins->output()));
masm.ma_vldr(Address(GlobalReg, addr), vd.singleOverlay(), scratch);
} else {
MOZ_ASSERT(mir->type() == MIRType::Double);
masm.ma_vldr(Address(GlobalReg, addr), ToFloatRegister(ins->output()), scratch);
}
}
void
CodeGeneratorARM::visitWasmLoadGlobalVarI64(LWasmLoadGlobalVarI64* ins)
{
const MWasmLoadGlobalVar* mir = ins->mir();
unsigned addr = mir->globalDataOffset() - WasmGlobalRegBias;
MOZ_ASSERT(mir->type() == MIRType::Int64);
Register64 output = ToOutRegister64(ins);
ScratchRegisterScope scratch(masm);
masm.ma_dtr(IsLoad, GlobalReg, Imm32(addr + INT64LOW_OFFSET), output.low, scratch);
masm.ma_dtr(IsLoad, GlobalReg, Imm32(addr + INT64HIGH_OFFSET), output.high, scratch);
}
void
CodeGeneratorARM::visitWasmStoreGlobalVar(LWasmStoreGlobalVar* ins)
{
const MWasmStoreGlobalVar* mir = ins->mir();
MIRType type = mir->value()->type();
ScratchRegisterScope scratch(masm);
unsigned addr = mir->globalDataOffset() - WasmGlobalRegBias;
if (type == MIRType::Int32) {
masm.ma_dtr(IsStore, GlobalReg, Imm32(addr), ToRegister(ins->value()), scratch);
} else if (type == MIRType::Float32) {
VFPRegister vd(ToFloatRegister(ins->value()));
masm.ma_vstr(vd.singleOverlay(), Address(GlobalReg, addr), scratch);
} else {
MOZ_ASSERT(type == MIRType::Double);
masm.ma_vstr(ToFloatRegister(ins->value()), Address(GlobalReg, addr), scratch);
}
}
void
CodeGeneratorARM::visitWasmStoreGlobalVarI64(LWasmStoreGlobalVarI64* ins)
{
const MWasmStoreGlobalVar* mir = ins->mir();
unsigned addr = mir->globalDataOffset() - WasmGlobalRegBias;
MOZ_ASSERT (mir->value()->type() == MIRType::Int64);
Register64 input = ToRegister64(ins->value());
ScratchRegisterScope scratch(masm);
masm.ma_dtr(IsStore, GlobalReg, Imm32(addr + INT64LOW_OFFSET), input.low, scratch);
masm.ma_dtr(IsStore, GlobalReg, Imm32(addr + INT64HIGH_OFFSET), input.high, scratch);
}
void
CodeGeneratorARM::visitNegI(LNegI* ins)
{

View file

@ -1525,13 +1525,11 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
}
void loadWasmGlobalPtr(uint32_t globalDataOffset, Register dest) {
loadPtr(Address(GlobalReg, globalDataOffset - WasmGlobalRegBias), dest);
loadPtr(Address(WasmTlsReg, offsetof(wasm::TlsData, globalArea) + globalDataOffset), dest);
}
void loadWasmPinnedRegsFromTls() {
ScratchRegisterScope scratch(asMasm());
ma_ldr(Address(WasmTlsReg, offsetof(wasm::TlsData, memoryBase)), HeapReg, scratch);
ma_ldr(Address(WasmTlsReg, offsetof(wasm::TlsData, globalData)), GlobalReg, scratch);
ma_add(Imm32(WasmGlobalRegBias), GlobalReg, scratch);
}
// Instrumentation for entering and leaving the profiler.

View file

@ -82,7 +82,6 @@ static constexpr Register IntArgReg4 = { Registers::x4 };
static constexpr Register IntArgReg5 = { Registers::x5 };
static constexpr Register IntArgReg6 = { Registers::x6 };
static constexpr Register IntArgReg7 = { Registers::x7 };
static constexpr Register GlobalReg = { Registers::x20 };
static constexpr Register HeapReg = { Registers::x21 };
static constexpr Register HeapLenReg = { Registers::x22 };
@ -169,7 +168,6 @@ static_assert(CodeAlignment % SimdMemoryAlignment == 0,
"alignment for SIMD constants.");
static const uint32_t WasmStackAlignment = SimdMemoryAlignment;
static const int32_t WasmGlobalRegBias = 1024;
// Does this architecture support SIMD conversions between Uint32x4 and Float32x4?
static constexpr bool SupportsUint32x4FloatConversions = false;

View file

@ -619,7 +619,6 @@ getBase(U* mir)
{
switch (mir->base()) {
case U::Heap: return HeapReg;
case U::Global: return GlobalReg;
}
return InvalidReg;
}
@ -696,18 +695,6 @@ CodeGeneratorARM64::visitEffectiveAddress(LEffectiveAddress* ins)
MOZ_CRASH("visitEffectiveAddress");
}
void
CodeGeneratorARM64::visitWasmLoadGlobalVar(LWasmLoadGlobalVar* ins)
{
MOZ_CRASH("visitWasmLoadGlobalVar");
}
void
CodeGeneratorARM64::visitWasmStoreGlobalVar(LWasmStoreGlobalVar* ins)
{
MOZ_CRASH("visitWasmStoreGlobalVar");
}
void
CodeGeneratorARM64::visitNegI(LNegI* ins)
{

View file

@ -205,9 +205,6 @@ class CodeGeneratorARM64 : public CodeGeneratorShared
void visitAsmJSAtomicBinopHeap(LAsmJSAtomicBinopHeap* ins);
void visitWasmStackArg(LWasmStackArg* ins);
void visitWasmLoadGlobalVar(LWasmLoadGlobalVar* ins);
void visitWasmStoreGlobalVar(LWasmStoreGlobalVar* ins);
void generateInvalidateEpilogue();
void setReturnDoubleRegs(LiveRegisterSet* regs);

View file

@ -2252,12 +2252,10 @@ class MacroAssemblerCompat : public vixl::MacroAssembler
}
void loadWasmGlobalPtr(uint32_t globalDataOffset, Register dest) {
loadPtr(Address(GlobalReg, globalDataOffset - WasmGlobalRegBias), dest);
loadPtr(Address(WasmTlsReg, offsetof(wasm::TlsData, globalArea) + globalDataOffset), dest);
}
void loadWasmPinnedRegsFromTls() {
loadPtr(Address(WasmTlsReg, offsetof(wasm::TlsData, memoryBase)), HeapReg);
loadPtr(Address(WasmTlsReg, offsetof(wasm::TlsData, globalData)), GlobalReg);
adds32(Imm32(WasmGlobalRegBias), GlobalReg);
}
// Overwrites the payload bits of a dest register containing a Value.

View file

@ -2132,11 +2132,9 @@ CodeGeneratorMIPSShared::visitAsmJSLoadHeap(LAsmJSLoadHeap* ins)
// Offset is out of range. Load default values.
if (isFloat) {
if (size == 32)
masm.loadFloat32(Address(GlobalReg, wasm::NaN32GlobalDataOffset - WasmGlobalRegBias),
ToFloatRegister(out));
masm.loadConstantFloat32(float(GenericNaN()), ToFloatRegister(out));
else
masm.loadDouble(Address(GlobalReg, wasm::NaN64GlobalDataOffset - WasmGlobalRegBias),
ToFloatRegister(out));
masm.loadConstantDouble(GenericNaN(), ToFloatRegister(out));
} else {
masm.move32(Imm32(0), ToRegister(out));
}
@ -2469,34 +2467,6 @@ CodeGeneratorMIPSShared::visitEffectiveAddress(LEffectiveAddress* ins)
masm.computeEffectiveAddress(address, output);
}
void
CodeGeneratorMIPSShared::visitWasmLoadGlobalVar(LWasmLoadGlobalVar* ins)
{
const MWasmLoadGlobalVar* mir = ins->mir();
unsigned addr = mir->globalDataOffset() - WasmGlobalRegBias;
if (mir->type() == MIRType::Int32)
masm.load32(Address(GlobalReg, addr), ToRegister(ins->output()));
else if (mir->type() == MIRType::Float32)
masm.loadFloat32(Address(GlobalReg, addr), ToFloatRegister(ins->output()));
else
masm.loadDouble(Address(GlobalReg, addr), ToFloatRegister(ins->output()));
}
void
CodeGeneratorMIPSShared::visitWasmStoreGlobalVar(LWasmStoreGlobalVar* ins)
{
const MWasmStoreGlobalVar* mir = ins->mir();
MOZ_ASSERT(IsNumberType(mir->value()->type()));
unsigned addr = mir->globalDataOffset() - WasmGlobalRegBias;
if (mir->value()->type() == MIRType::Int32)
masm.store32(ToRegister(ins->value()), Address(GlobalReg, addr));
else if (mir->value()->type() == MIRType::Float32)
masm.storeFloat32(ToFloatRegister(ins->value()), Address(GlobalReg, addr));
else
masm.storeDouble(ToFloatRegister(ins->value()), Address(GlobalReg, addr));
}
void
CodeGeneratorMIPSShared::visitNegI(LNegI* ins)
{

View file

@ -186,8 +186,6 @@ class CodeGeneratorMIPSShared : public CodeGeneratorShared
virtual void visitTruncateFToInt32(LTruncateFToInt32* ins);
void visitWasmTruncateToInt32(LWasmTruncateToInt32* lir);
void visitWasmLoadGlobalVar(LWasmLoadGlobalVar* ins);
void visitWasmStoreGlobalVar(LWasmStoreGlobalVar* ins);
// Out of line visitors.
virtual void visitOutOfLineBailout(OutOfLineBailout* ool) = 0;

View file

@ -618,30 +618,6 @@ CodeGeneratorMIPS::visitWasmUnalignedStoreI64(LWasmUnalignedStoreI64* lir)
emitWasmStoreI64(lir);
}
void
CodeGeneratorMIPS::visitWasmLoadGlobalVarI64(LWasmLoadGlobalVarI64* ins)
{
const MWasmLoadGlobalVar* mir = ins->mir();
unsigned addr = mir->globalDataOffset() - WasmGlobalRegBias;
MOZ_ASSERT(mir->type() == MIRType::Int64);
Register64 output = ToOutRegister64(ins);
masm.load32(Address(GlobalReg, addr + INT64LOW_OFFSET), output.low);
masm.load32(Address(GlobalReg, addr + INT64HIGH_OFFSET), output.high);
}
void
CodeGeneratorMIPS::visitWasmStoreGlobalVarI64(LWasmStoreGlobalVarI64* ins)
{
const MWasmStoreGlobalVar* mir = ins->mir();
unsigned addr = mir->globalDataOffset() - WasmGlobalRegBias;
MOZ_ASSERT (mir->value()->type() == MIRType::Int64);
Register64 input = ToRegister64(ins->value());
masm.store32(input.low, Address(GlobalReg, addr + INT64LOW_OFFSET));
masm.store32(input.high, Address(GlobalReg, addr + INT64HIGH_OFFSET));
}
void
CodeGeneratorMIPS::visitWasmSelectI64(LWasmSelectI64* lir)
{

View file

@ -50,8 +50,6 @@ class CodeGeneratorMIPS : public CodeGeneratorMIPSShared
void visitWasmUnalignedLoadI64(LWasmUnalignedLoadI64* lir);
void visitWasmStoreI64(LWasmStoreI64* ins);
void visitWasmUnalignedStoreI64(LWasmUnalignedStoreI64* ins);
void visitWasmLoadGlobalVarI64(LWasmLoadGlobalVarI64* ins);
void visitWasmStoreGlobalVarI64(LWasmStoreGlobalVarI64* ins);
void visitWasmSelectI64(LWasmSelectI64* lir);
void visitWasmReinterpretFromI64(LWasmReinterpretFromI64* lir);
void visitWasmReinterpretToI64(LWasmReinterpretToI64* lir);

View file

@ -547,24 +547,6 @@ CodeGeneratorMIPS64::visitWasmUnalignedStoreI64(LWasmUnalignedStoreI64* lir)
emitWasmStoreI64(lir);
}
void
CodeGeneratorMIPS64::visitWasmLoadGlobalVarI64(LWasmLoadGlobalVarI64* ins)
{
const MWasmLoadGlobalVar* mir = ins->mir();
unsigned addr = mir->globalDataOffset() - WasmGlobalRegBias;
MOZ_ASSERT(mir->type() == MIRType::Int64);
masm.load64(Address(GlobalReg, addr), ToOutRegister64(ins));
}
void
CodeGeneratorMIPS64::visitWasmStoreGlobalVarI64(LWasmStoreGlobalVarI64* ins)
{
const MWasmStoreGlobalVar* mir = ins->mir();
unsigned addr = mir->globalDataOffset() - WasmGlobalRegBias;
MOZ_ASSERT(mir->value()->type() == MIRType::Int64);
masm.store64(ToRegister64(ins->value()), Address(GlobalReg, addr));
}
void
CodeGeneratorMIPS64::visitWasmSelectI64(LWasmSelectI64* lir)
{

View file

@ -56,8 +56,6 @@ class CodeGeneratorMIPS64 : public CodeGeneratorMIPSShared
void visitWasmUnalignedLoadI64(LWasmUnalignedLoadI64* lir);
void visitWasmStoreI64(LWasmStoreI64* ins);
void visitWasmUnalignedStoreI64(LWasmUnalignedStoreI64* ins);
void visitWasmLoadGlobalVarI64(LWasmLoadGlobalVarI64* ins);
void visitWasmStoreGlobalVarI64(LWasmStoreGlobalVarI64* ins);
void visitWasmSelectI64(LWasmSelectI64* ins);
void visitWasmReinterpretFromI64(LWasmReinterpretFromI64* lir);
void visitWasmReinterpretToI64(LWasmReinterpretToI64* lir);

View file

@ -39,7 +39,6 @@ static constexpr Register IntArgReg0 = { Registers::invalid_reg };
static constexpr Register IntArgReg1 = { Registers::invalid_reg };
static constexpr Register IntArgReg2 = { Registers::invalid_reg };
static constexpr Register IntArgReg3 = { Registers::invalid_reg };
static constexpr Register GlobalReg = { Registers::invalid_reg };
static constexpr Register HeapReg = { Registers::invalid_reg };
static constexpr Register WasmIonExitRegCallee = { Registers::invalid_reg };

View file

@ -798,7 +798,6 @@ class AssemblerShared
wasm::MemoryAccessVector memoryAccesses_;
wasm::MemoryPatchVector memoryPatches_;
wasm::BoundsCheckVector boundsChecks_;
wasm::GlobalAccessVector globalAccesses_;
wasm::SymbolicAccessVector symbolicAccesses_;
protected:
@ -879,9 +878,6 @@ class AssemblerShared
void append(wasm::BoundsCheck check) { enoughMemory_ &= boundsChecks_.append(check); }
wasm::BoundsCheckVector&& extractBoundsChecks() { return Move(boundsChecks_); }
void append(wasm::GlobalAccess access) { enoughMemory_ &= globalAccesses_.append(access); }
const wasm::GlobalAccessVector& globalAccesses() const { return globalAccesses_; }
void append(wasm::SymbolicAccess access) { enoughMemory_ &= symbolicAccesses_.append(access); }
size_t numSymbolicAccesses() const { return symbolicAccesses_.length(); }
wasm::SymbolicAccess symbolicAccess(size_t i) const { return symbolicAccesses_[i]; }
@ -928,11 +924,6 @@ class AssemblerShared
for (; i < boundsChecks_.length(); i++)
boundsChecks_[i].offsetBy(delta);
i = globalAccesses_.length();
enoughMemory_ &= globalAccesses_.appendAll(other.globalAccesses_);
for (; i < globalAccesses_.length(); i++)
globalAccesses_[i].patchAt.offsetBy(delta);
i = symbolicAccesses_.length();
enoughMemory_ &= symbolicAccesses_.appendAll(other.symbolicAccesses_);
for (; i < symbolicAccesses_.length(); i++)

View file

@ -1529,6 +1529,104 @@ CodeGeneratorShared::emitWasmCallBase(LWasmCallBase* ins)
masm.reserveStack(mir->spIncrement());
}
void
CodeGeneratorShared::visitWasmLoadGlobalVar(LWasmLoadGlobalVar* ins)
{
MWasmLoadGlobalVar* mir = ins->mir();
MIRType type = mir->type();
MOZ_ASSERT(IsNumberType(type) || IsSimdType(type));
Register tls = ToRegister(ins->tlsPtr());
Address addr(tls, offsetof(wasm::TlsData, globalArea) + mir->globalDataOffset());
switch (type) {
case MIRType::Int32:
masm.load32(addr, ToRegister(ins->output()));
break;
case MIRType::Float32:
masm.loadFloat32(addr, ToFloatRegister(ins->output()));
break;
case MIRType::Double:
masm.loadDouble(addr, ToFloatRegister(ins->output()));
break;
// Aligned access: code is aligned on PageSize + there is padding
// before the global data section.
case MIRType::Int8x16:
case MIRType::Int16x8:
case MIRType::Int32x4:
case MIRType::Bool8x16:
case MIRType::Bool16x8:
case MIRType::Bool32x4:
masm.loadInt32x4(addr, ToFloatRegister(ins->output()));
break;
case MIRType::Float32x4:
masm.loadFloat32x4(addr, ToFloatRegister(ins->output()));
break;
default:
MOZ_CRASH("unexpected type in visitWasmLoadGlobalVar");
}
}
void
CodeGeneratorShared::visitWasmStoreGlobalVar(LWasmStoreGlobalVar* ins)
{
MWasmStoreGlobalVar* mir = ins->mir();
MIRType type = mir->value()->type();
MOZ_ASSERT(IsNumberType(type) || IsSimdType(type));
Register tls = ToRegister(ins->tlsPtr());
Address addr(tls, offsetof(wasm::TlsData, globalArea) + mir->globalDataOffset());
switch (type) {
case MIRType::Int32:
masm.store32(ToRegister(ins->value()), addr);
break;
case MIRType::Float32:
masm.storeFloat32(ToFloatRegister(ins->value()), addr);
break;
case MIRType::Double:
masm.storeDouble(ToFloatRegister(ins->value()), addr);
break;
// Aligned access: code is aligned on PageSize + there is padding
// before the global data section.
case MIRType::Int32x4:
case MIRType::Bool32x4:
masm.storeInt32x4(ToFloatRegister(ins->value()), addr);
break;
case MIRType::Float32x4:
masm.storeFloat32x4(ToFloatRegister(ins->value()), addr);
break;
default:
MOZ_CRASH("unexpected type in visitWasmStoreGlobalVar");
}
}
void
CodeGeneratorShared::visitWasmLoadGlobalVarI64(LWasmLoadGlobalVarI64* ins)
{
MWasmLoadGlobalVar* mir = ins->mir();
MOZ_ASSERT(mir->type() == MIRType::Int64);
Register tls = ToRegister(ins->tlsPtr());
Address addr(tls, offsetof(wasm::TlsData, globalArea) + mir->globalDataOffset());
Register64 output = ToOutRegister64(ins);
masm.load64(addr, output);
}
void
CodeGeneratorShared::visitWasmStoreGlobalVarI64(LWasmStoreGlobalVarI64* ins)
{
MWasmStoreGlobalVar* mir = ins->mir();
MOZ_ASSERT(mir->value()->type() == MIRType::Int64);
Register tls = ToRegister(ins->tlsPtr());
Address addr(tls, offsetof(wasm::TlsData, globalArea) + mir->globalDataOffset());
Register64 value = ToRegister64(ins->value());
masm.store64(value, addr);
}
void
CodeGeneratorShared::emitPreBarrier(Register base, const LAllocation* index, int32_t offsetAdjustment)
{

View file

@ -356,6 +356,10 @@ class CodeGeneratorShared : public LElementVisitor
void emitTruncateFloat32(FloatRegister src, Register dest, MInstruction* mir);
void emitWasmCallBase(LWasmCallBase* ins);
void visitWasmLoadGlobalVar(LWasmLoadGlobalVar* ins);
void visitWasmStoreGlobalVar(LWasmStoreGlobalVar* ins);
void visitWasmLoadGlobalVarI64(LWasmLoadGlobalVarI64* ins);
void visitWasmStoreGlobalVarI64(LWasmStoreGlobalVarI64* ins);
void emitPreBarrier(Register base, const LAllocation* index, int32_t offsetAdjustment);
void emitPreBarrier(Address address);

View file

@ -7751,30 +7751,43 @@ class LAsmJSAtomicBinopHeapForEffect : public LInstructionHelper<0, 2, 5>
}
};
class LWasmLoadGlobalVar : public LInstructionHelper<1, 0, 0>
class LWasmLoadGlobalVar : public LInstructionHelper<1, 1, 0>
{
public:
LIR_HEADER(WasmLoadGlobalVar);
explicit LWasmLoadGlobalVar(const LAllocation& tlsPtr) {
setOperand(0, tlsPtr);
}
MWasmLoadGlobalVar* mir() const {
return mir_->toWasmLoadGlobalVar();
}
const LAllocation* tlsPtr() {
return getOperand(0);
}
};
class LWasmLoadGlobalVarI64 : public LInstructionHelper<INT64_PIECES, 0, 0>
class LWasmLoadGlobalVarI64 : public LInstructionHelper<INT64_PIECES, 1, 0>
{
public:
LIR_HEADER(WasmLoadGlobalVarI64);
explicit LWasmLoadGlobalVarI64(const LAllocation& tlsPtr) {
setOperand(0, tlsPtr);
}
MWasmLoadGlobalVar* mir() const {
return mir_->toWasmLoadGlobalVar();
}
const LAllocation* tlsPtr() {
return getOperand(0);
}
};
class LWasmStoreGlobalVar : public LInstructionHelper<0, 1, 0>
class LWasmStoreGlobalVar : public LInstructionHelper<0, 2, 0>
{
public:
LIR_HEADER(WasmStoreGlobalVar);
explicit LWasmStoreGlobalVar(const LAllocation& value) {
explicit LWasmStoreGlobalVar(const LAllocation& value, const LAllocation& tlsPtr) {
setOperand(0, value);
setOperand(1, tlsPtr);
}
MWasmStoreGlobalVar* mir() const {
return mir_->toWasmStoreGlobalVar();
@ -7782,22 +7795,28 @@ class LWasmStoreGlobalVar : public LInstructionHelper<0, 1, 0>
const LAllocation* value() {
return getOperand(0);
}
const LAllocation* tlsPtr() {
return getOperand(1);
}
};
class LWasmStoreGlobalVarI64 : public LInstructionHelper<0, INT64_PIECES, 0>
class LWasmStoreGlobalVarI64 : public LInstructionHelper<0, INT64_PIECES + 1, 0>
{
public:
LIR_HEADER(WasmStoreGlobalVarI64);
explicit LWasmStoreGlobalVarI64(const LInt64Allocation& value) {
explicit LWasmStoreGlobalVarI64(const LInt64Allocation& value, const LAllocation& tlsPtr) {
setInt64Operand(0, value);
setOperand(INT64_PIECES, tlsPtr);
}
MWasmStoreGlobalVar* mir() const {
return mir_->toWasmStoreGlobalVar();
}
static const uint32_t InputIndex = 0;
const LInt64Allocation value() {
return getInt64Operand(InputIndex);
return getInt64Operand(0);
}
const LAllocation* tlsPtr() {
return getOperand(INT64_PIECES);
}
};

View file

@ -653,99 +653,6 @@ CodeGeneratorX64::visitAsmJSAtomicBinopHeapForEffect(LAsmJSAtomicBinopHeapForEff
atomicBinopToTypedIntArray(op, accessType, ToRegister(value), srcAddr);
}
void
CodeGeneratorX64::visitWasmLoadGlobalVar(LWasmLoadGlobalVar* ins)
{
MWasmLoadGlobalVar* mir = ins->mir();
MIRType type = mir->type();
MOZ_ASSERT(IsNumberType(type) || IsSimdType(type));
CodeOffset label;
switch (type) {
case MIRType::Int32:
label = masm.loadRipRelativeInt32(ToRegister(ins->output()));
break;
case MIRType::Float32:
label = masm.loadRipRelativeFloat32(ToFloatRegister(ins->output()));
break;
case MIRType::Double:
label = masm.loadRipRelativeDouble(ToFloatRegister(ins->output()));
break;
// Aligned access: code is aligned on PageSize + there is padding
// before the global data section.
case MIRType::Int8x16:
case MIRType::Int16x8:
case MIRType::Int32x4:
case MIRType::Bool8x16:
case MIRType::Bool16x8:
case MIRType::Bool32x4:
label = masm.loadRipRelativeInt32x4(ToFloatRegister(ins->output()));
break;
case MIRType::Float32x4:
label = masm.loadRipRelativeFloat32x4(ToFloatRegister(ins->output()));
break;
default:
MOZ_CRASH("unexpected type in visitWasmLoadGlobalVar");
}
masm.append(wasm::GlobalAccess(label, mir->globalDataOffset()));
}
void
CodeGeneratorX64::visitWasmLoadGlobalVarI64(LWasmLoadGlobalVarI64* ins)
{
MWasmLoadGlobalVar* mir = ins->mir();
MOZ_ASSERT(mir->type() == MIRType::Int64);
CodeOffset label = masm.loadRipRelativeInt64(ToRegister(ins->output()));
masm.append(wasm::GlobalAccess(label, mir->globalDataOffset()));
}
void
CodeGeneratorX64::visitWasmStoreGlobalVar(LWasmStoreGlobalVar* ins)
{
MWasmStoreGlobalVar* mir = ins->mir();
MIRType type = mir->value()->type();
MOZ_ASSERT(IsNumberType(type) || IsSimdType(type));
CodeOffset label;
switch (type) {
case MIRType::Int32:
label = masm.storeRipRelativeInt32(ToRegister(ins->value()));
break;
case MIRType::Float32:
label = masm.storeRipRelativeFloat32(ToFloatRegister(ins->value()));
break;
case MIRType::Double:
label = masm.storeRipRelativeDouble(ToFloatRegister(ins->value()));
break;
// Aligned access: code is aligned on PageSize + there is padding
// before the global data section.
case MIRType::Int32x4:
case MIRType::Bool32x4:
label = masm.storeRipRelativeInt32x4(ToFloatRegister(ins->value()));
break;
case MIRType::Float32x4:
label = masm.storeRipRelativeFloat32x4(ToFloatRegister(ins->value()));
break;
default:
MOZ_CRASH("unexpected type in visitWasmStoreGlobalVar");
}
masm.append(wasm::GlobalAccess(label, mir->globalDataOffset()));
}
void
CodeGeneratorX64::visitWasmStoreGlobalVarI64(LWasmStoreGlobalVarI64* ins)
{
MWasmStoreGlobalVar* mir = ins->mir();
MOZ_ASSERT(mir->value()->type() == MIRType::Int64);
Register value = ToRegister(ins->getOperand(LWasmStoreGlobalVarI64::InputIndex));
CodeOffset label = masm.storeRipRelativeInt64(value);
masm.append(wasm::GlobalAccess(label, mir->globalDataOffset()));
}
void
CodeGeneratorX64::visitTruncateDToInt32(LTruncateDToInt32* ins)
{

View file

@ -61,10 +61,6 @@ class CodeGeneratorX64 : public CodeGeneratorX86Shared
void visitWasmLoadI64(LWasmLoadI64* ins);
void visitWasmStore(LWasmStore* ins);
void visitWasmStoreI64(LWasmStoreI64* ins);
void visitWasmLoadGlobalVar(LWasmLoadGlobalVar* ins);
void visitWasmStoreGlobalVar(LWasmStoreGlobalVar* ins);
void visitWasmLoadGlobalVarI64(LWasmLoadGlobalVarI64* ins);
void visitWasmStoreGlobalVarI64(LWasmStoreGlobalVarI64* ins);
void visitWasmSelectI64(LWasmSelectI64* ins);
void visitWasmCall(LWasmCall* ins);
void visitWasmCallI64(LWasmCallI64* ins);

View file

@ -582,6 +582,9 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
void loadPtr(const Address& address, Register dest) {
movq(Operand(address), dest);
}
void load64(const Address& address, Register dest) {
movq(Operand(address), dest);
}
void loadPtr(const Operand& src, Register dest) {
movq(src, dest);
}
@ -627,6 +630,9 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
void storePtr(Register src, const Address& address) {
movq(src, Operand(address));
}
void store64(Register src, const Address& address) {
movq(src, Operand(address));
}
void storePtr(Register src, const BaseIndex& address) {
movq(src, Operand(address));
}
@ -897,8 +903,7 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
Label* oolRejoin, FloatRegister tempDouble);
void loadWasmGlobalPtr(uint32_t globalDataOffset, Register dest) {
CodeOffset label = loadRipRelativeInt64(dest);
append(wasm::GlobalAccess(label, globalDataOffset));
loadPtr(Address(WasmTlsReg, offsetof(wasm::TlsData, globalArea) + globalDataOffset), dest);
}
void loadWasmPinnedRegsFromTls() {
loadPtr(Address(WasmTlsReg, offsetof(wasm::TlsData, memoryBase)), HeapReg);

View file

@ -809,6 +809,19 @@ class MacroAssemblerX86Shared : public Assembler
vcvtsd2ss(src, dest, dest);
}
void loadInt32x4(const Address& addr, FloatRegister dest) {
vmovdqa(Operand(addr), dest);
}
void loadFloat32x4(const Address& addr, FloatRegister dest) {
vmovaps(Operand(addr), dest);
}
void storeInt32x4(FloatRegister src, const Address& addr) {
vmovdqa(src, Operand(addr));
}
void storeFloat32x4(FloatRegister src, const Address& addr) {
vmovaps(src, Operand(addr));
}
void convertFloat32x4ToInt32x4(FloatRegister src, FloatRegister dest) {
// Note that if the conversion failed (because the converted
// result is larger than the maximum signed int32, or less than the

View file

@ -663,68 +663,6 @@ CodeGeneratorX86::visitWasmLoadGlobalVar(LWasmLoadGlobalVar* ins)
masm.append(wasm::GlobalAccess(label, mir->globalDataOffset()));
}
void
CodeGeneratorX86::visitWasmLoadGlobalVarI64(LWasmLoadGlobalVarI64* ins)
{
MWasmLoadGlobalVar* mir = ins->mir();
MOZ_ASSERT(mir->type() == MIRType::Int64);
Register64 output = ToOutRegister64(ins);
CodeOffset labelLow = masm.movlWithPatch(PatchedAbsoluteAddress(), output.low);
masm.append(wasm::GlobalAccess(labelLow, mir->globalDataOffset() + INT64LOW_OFFSET));
CodeOffset labelHigh = masm.movlWithPatch(PatchedAbsoluteAddress(), output.high);
masm.append(wasm::GlobalAccess(labelHigh, mir->globalDataOffset() + INT64HIGH_OFFSET));
}
void
CodeGeneratorX86::visitWasmStoreGlobalVar(LWasmStoreGlobalVar* ins)
{
MWasmStoreGlobalVar* mir = ins->mir();
MIRType type = mir->value()->type();
MOZ_ASSERT(IsNumberType(type) || IsSimdType(type));
CodeOffset label;
switch (type) {
case MIRType::Int32:
label = masm.movlWithPatch(ToRegister(ins->value()), PatchedAbsoluteAddress());
break;
case MIRType::Float32:
label = masm.vmovssWithPatch(ToFloatRegister(ins->value()), PatchedAbsoluteAddress());
break;
case MIRType::Double:
label = masm.vmovsdWithPatch(ToFloatRegister(ins->value()), PatchedAbsoluteAddress());
break;
// Aligned access: code is aligned on PageSize + there is padding
// before the global data section.
case MIRType::Int32x4:
case MIRType::Bool32x4:
label = masm.vmovdqaWithPatch(ToFloatRegister(ins->value()), PatchedAbsoluteAddress());
break;
case MIRType::Float32x4:
label = masm.vmovapsWithPatch(ToFloatRegister(ins->value()), PatchedAbsoluteAddress());
break;
default:
MOZ_CRASH("unexpected type in visitWasmStoreGlobalVar");
}
masm.append(wasm::GlobalAccess(label, mir->globalDataOffset()));
}
void
CodeGeneratorX86::visitWasmStoreGlobalVarI64(LWasmStoreGlobalVarI64* ins)
{
MWasmStoreGlobalVar* mir = ins->mir();
MOZ_ASSERT(mir->value()->type() == MIRType::Int64);
Register64 input = ToRegister64(ins->value());
CodeOffset labelLow = masm.movlWithPatch(input.low, PatchedAbsoluteAddress());
masm.append(wasm::GlobalAccess(labelLow, mir->globalDataOffset() + INT64LOW_OFFSET));
CodeOffset labelHigh = masm.movlWithPatch(input.high, PatchedAbsoluteAddress());
masm.append(wasm::GlobalAccess(labelHigh, mir->globalDataOffset() + INT64HIGH_OFFSET));
}
namespace js {
namespace jit {

View file

@ -55,10 +55,6 @@ class CodeGeneratorX86 : public CodeGeneratorX86Shared
void visitWasmLoadI64(LWasmLoadI64* ins);
void visitWasmStore(LWasmStore* ins);
void visitWasmStoreI64(LWasmStoreI64* ins);
void visitWasmLoadGlobalVar(LWasmLoadGlobalVar* ins);
void visitWasmLoadGlobalVarI64(LWasmLoadGlobalVarI64* ins);
void visitWasmStoreGlobalVar(LWasmStoreGlobalVar* ins);
void visitWasmStoreGlobalVarI64(LWasmStoreGlobalVarI64* ins);
void visitAsmJSLoadHeap(LAsmJSLoadHeap* ins);
void visitAsmJSStoreHeap(LAsmJSStoreHeap* ins);
void visitAsmJSCompareExchangeHeap(LAsmJSCompareExchangeHeap* ins);

View file

@ -864,8 +864,7 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
inline void ensureDouble(const ValueOperand& source, FloatRegister dest, Label* failure);
void loadWasmGlobalPtr(uint32_t globalDataOffset, Register dest) {
CodeOffset label = movlWithPatch(PatchedAbsoluteAddress(), dest);
append(wasm::GlobalAccess(label, globalDataOffset));
loadPtr(Address(WasmTlsReg, offsetof(wasm::TlsData, globalArea) + globalDataOffset), dest);
}
void loadWasmPinnedRegsFromTls() {
// x86 doesn't have any pinned registers.

View file

@ -3360,174 +3360,65 @@ class BaseCompiler
//
// Global variable access.
// CodeGenerator{X86,X64}::visitWasmLoadGlobal()
uint32_t globalToTlsOffset(uint32_t globalOffset) {
return offsetof(TlsData, globalArea) + globalOffset;
}
void loadGlobalVarI32(unsigned globalDataOffset, RegI32 r)
{
#if defined(JS_CODEGEN_X64)
CodeOffset label = masm.loadRipRelativeInt32(r.reg);
masm.append(GlobalAccess(label, globalDataOffset));
#elif defined(JS_CODEGEN_X86)
CodeOffset label = masm.movlWithPatch(PatchedAbsoluteAddress(), r.reg);
masm.append(GlobalAccess(label, globalDataOffset));
#elif defined(JS_CODEGEN_ARM)
ScratchRegisterScope scratch(*this); // Really must be the ARM scratchreg
unsigned addr = globalDataOffset - WasmGlobalRegBias;
masm.ma_dtr(js::jit::IsLoad, GlobalReg, Imm32(addr), r.reg, scratch);
#elif defined(JS_CODEGEN_LOONGARCH64)
unsigned addr = globalDataOffset - WasmGlobalRegBias;
masm.load32(Address(GlobalReg, addr), r.reg);
#else
MOZ_CRASH("BaseCompiler platform hook: loadGlobalVarI32");
#endif
ScratchI32 tmp(*this);
loadFromFramePtr(tmp, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer));
masm.load32(Address(tmp, globalToTlsOffset(globalDataOffset)), r);
}
void loadGlobalVarI64(unsigned globalDataOffset, RegI64 r)
{
#if defined(JS_CODEGEN_X64)
CodeOffset label = masm.loadRipRelativeInt64(r.reg.reg);
masm.append(GlobalAccess(label, globalDataOffset));
#elif defined(JS_CODEGEN_X86)
CodeOffset labelLow = masm.movlWithPatch(PatchedAbsoluteAddress(), r.reg.low);
masm.append(GlobalAccess(labelLow, globalDataOffset + INT64LOW_OFFSET));
CodeOffset labelHigh = masm.movlWithPatch(PatchedAbsoluteAddress(), r.reg.high);
masm.append(GlobalAccess(labelHigh, globalDataOffset + INT64HIGH_OFFSET));
#elif defined(JS_CODEGEN_ARM)
ScratchRegisterScope scratch(*this); // Really must be the ARM scratchreg
unsigned addr = globalDataOffset - WasmGlobalRegBias;
masm.ma_dtr(js::jit::IsLoad, GlobalReg, Imm32(addr + INT64LOW_OFFSET), r.reg.low, scratch);
masm.ma_dtr(js::jit::IsLoad, GlobalReg, Imm32(addr + INT64HIGH_OFFSET), r.reg.high,
scratch);
#elif defined(JS_CODEGEN_LOONGARCH64)
unsigned addr = globalDataOffset - WasmGlobalRegBias;
masm.load64(Address(GlobalReg, addr), r.reg);
#else
MOZ_CRASH("BaseCompiler platform hook: loadGlobalVarI64");
#endif
ScratchI32 tmp(*this);
loadFromFramePtr(tmp, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer));
masm.load64(Address(tmp, globalToTlsOffset(globalDataOffset)), r);
}
void loadGlobalVarF32(unsigned globalDataOffset, RegF32 r)
{
#if defined(JS_CODEGEN_X64)
CodeOffset label = masm.loadRipRelativeFloat32(r.reg);
masm.append(GlobalAccess(label, globalDataOffset));
#elif defined(JS_CODEGEN_X86)
CodeOffset label = masm.vmovssWithPatch(PatchedAbsoluteAddress(), r.reg);
masm.append(GlobalAccess(label, globalDataOffset));
#elif defined(JS_CODEGEN_ARM)
unsigned addr = globalDataOffset - WasmGlobalRegBias;
VFPRegister vd(r.reg);
masm.ma_vldr(VFPAddr(GlobalReg, VFPOffImm(addr)), vd.singleOverlay());
#elif defined(JS_CODEGEN_LOONGARCH64)
unsigned addr = globalDataOffset - WasmGlobalRegBias;
masm.loadFloat32(Address(GlobalReg, addr), r.reg);
#else
MOZ_CRASH("BaseCompiler platform hook: loadGlobalVarF32");
#endif
ScratchI32 tmp(*this);
loadFromFramePtr(tmp, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer));
masm.loadFloat32(Address(tmp, globalToTlsOffset(globalDataOffset)), r);
}
void loadGlobalVarF64(unsigned globalDataOffset, RegF64 r)
{
#if defined(JS_CODEGEN_X64)
CodeOffset label = masm.loadRipRelativeDouble(r.reg);
masm.append(GlobalAccess(label, globalDataOffset));
#elif defined(JS_CODEGEN_X86)
CodeOffset label = masm.vmovsdWithPatch(PatchedAbsoluteAddress(), r.reg);
masm.append(GlobalAccess(label, globalDataOffset));
#elif defined(JS_CODEGEN_ARM)
unsigned addr = globalDataOffset - WasmGlobalRegBias;
masm.ma_vldr(VFPAddr(GlobalReg, VFPOffImm(addr)), r.reg);
#elif defined(JS_CODEGEN_LOONGARCH64)
unsigned addr = globalDataOffset - WasmGlobalRegBias;
masm.loadDouble(Address(GlobalReg, addr), r.reg);
#else
MOZ_CRASH("BaseCompiler platform hook: loadGlobalVarF64");
#endif
ScratchI32 tmp(*this);
loadFromFramePtr(tmp, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer));
masm.loadDouble(Address(tmp, globalToTlsOffset(globalDataOffset)), r);
}
// CodeGeneratorX64::visitWasmStoreGlobal()
void storeGlobalVarI32(unsigned globalDataOffset, RegI32 r)
{
#if defined(JS_CODEGEN_X64)
CodeOffset label = masm.storeRipRelativeInt32(r.reg);
masm.append(GlobalAccess(label, globalDataOffset));
#elif defined(JS_CODEGEN_X86)
CodeOffset label = masm.movlWithPatch(r.reg, PatchedAbsoluteAddress());
masm.append(GlobalAccess(label, globalDataOffset));
#elif defined(JS_CODEGEN_ARM)
ScratchRegisterScope scratch(*this); // Really must be the ARM scratchreg
unsigned addr = globalDataOffset - WasmGlobalRegBias;
masm.ma_dtr(js::jit::IsStore, GlobalReg, Imm32(addr), r.reg, scratch);
#elif defined(JS_CODEGEN_LOONGARCH64)
unsigned addr = globalDataOffset - WasmGlobalRegBias;
masm.store32(r.reg, Address(GlobalReg, addr));
#else
MOZ_CRASH("BaseCompiler platform hook: storeGlobalVarI32");
#endif
ScratchI32 tmp(*this);
loadFromFramePtr(tmp, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer));
masm.store32(r, Address(tmp, globalToTlsOffset(globalDataOffset)));
}
void storeGlobalVarI64(unsigned globalDataOffset, RegI64 r)
{
#if defined(JS_CODEGEN_X64)
CodeOffset label = masm.storeRipRelativeInt64(r.reg.reg);
masm.append(GlobalAccess(label, globalDataOffset));
#elif defined(JS_CODEGEN_X86)
CodeOffset labelLow = masm.movlWithPatch(r.reg.low, PatchedAbsoluteAddress());
masm.append(GlobalAccess(labelLow, globalDataOffset + INT64LOW_OFFSET));
CodeOffset labelHigh = masm.movlWithPatch(r.reg.high, PatchedAbsoluteAddress());
masm.append(GlobalAccess(labelHigh, globalDataOffset + INT64HIGH_OFFSET));
#elif defined(JS_CODEGEN_ARM)
ScratchRegisterScope scratch(*this); // Really must be the ARM scratchreg
unsigned addr = globalDataOffset - WasmGlobalRegBias;
masm.ma_dtr(js::jit::IsStore, GlobalReg, Imm32(addr + INT64LOW_OFFSET), r.reg.low, scratch);
masm.ma_dtr(js::jit::IsStore, GlobalReg, Imm32(addr + INT64HIGH_OFFSET), r.reg.high,
scratch);
#elif defined(JS_CODEGEN_LOONGARCH64)
unsigned addr = globalDataOffset - WasmGlobalRegBias;
masm.store64(r.reg, Address(GlobalReg, addr));
#else
MOZ_CRASH("BaseCompiler platform hook: storeGlobalVarI64");
#endif
ScratchI32 tmp(*this);
loadFromFramePtr(tmp, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer));
masm.store64(r, Address(tmp, globalToTlsOffset(globalDataOffset)));
}
void storeGlobalVarF32(unsigned globalDataOffset, RegF32 r)
{
#if defined(JS_CODEGEN_X64)
CodeOffset label = masm.storeRipRelativeFloat32(r.reg);
masm.append(GlobalAccess(label, globalDataOffset));
#elif defined(JS_CODEGEN_X86)
CodeOffset label = masm.vmovssWithPatch(r.reg, PatchedAbsoluteAddress());
masm.append(GlobalAccess(label, globalDataOffset));
#elif defined(JS_CODEGEN_ARM)
unsigned addr = globalDataOffset - WasmGlobalRegBias;
VFPRegister vd(r.reg);
masm.ma_vstr(vd.singleOverlay(), VFPAddr(GlobalReg, VFPOffImm(addr)));
#elif defined(JS_CODEGEN_LOONGARCH64)
unsigned addr = globalDataOffset - WasmGlobalRegBias;
masm.storeFloat32(r.reg, Address(GlobalReg, addr));
#else
MOZ_CRASH("BaseCompiler platform hook: storeGlobalVarF32");
#endif
ScratchI32 tmp(*this);
loadFromFramePtr(tmp, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer));
masm.storeFloat32(r, Address(tmp, globalToTlsOffset(globalDataOffset)));
}
void storeGlobalVarF64(unsigned globalDataOffset, RegF64 r)
{
#if defined(JS_CODEGEN_X64)
CodeOffset label = masm.storeRipRelativeDouble(r.reg);
masm.append(GlobalAccess(label, globalDataOffset));
#elif defined(JS_CODEGEN_X86)
CodeOffset label = masm.vmovsdWithPatch(r.reg, PatchedAbsoluteAddress());
masm.append(GlobalAccess(label, globalDataOffset));
#elif defined(JS_CODEGEN_ARM)
unsigned addr = globalDataOffset - WasmGlobalRegBias;
masm.ma_vstr(r.reg, VFPAddr(GlobalReg, VFPOffImm(addr)));
#elif defined(JS_CODEGEN_LOONGARCH64)
unsigned addr = globalDataOffset - WasmGlobalRegBias;
masm.storeDouble(r.reg, Address(GlobalReg, addr));
#else
MOZ_CRASH("BaseCompiler platform hook: storeGlobalVarF64");
#endif
ScratchI32 tmp(*this);
loadFromFramePtr(tmp, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer));
masm.storeDouble(r, Address(tmp, globalToTlsOffset(globalDataOffset)));
}
//////////////////////////////////////////////////////////////////////
@ -8072,18 +7963,15 @@ BaseCompiler::BaseCompiler(const ModuleEnvironment& env,
availGPR_.take(HeapReg);
#elif defined(JS_CODEGEN_ARM)
availGPR_.take(HeapReg);
availGPR_.take(GlobalReg);
availGPR_.take(ScratchRegARM);
#elif defined(JS_CODEGEN_ARM64)
availGPR_.take(HeapReg);
availGPR_.take(HeapLenReg);
availGPR_.take(GlobalReg);
#elif defined(JS_CODEGEN_X86)
availGPR_.take(ScratchRegX86);
#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) || \
defined(JS_CODEGEN_LOONGARCH64)
availGPR_.take(HeapReg);
availGPR_.take(GlobalReg);
#endif
}

View file

@ -342,13 +342,6 @@ enum class Op
Limit
};
// Static offsets into the global data of every module that is compiled.
static const unsigned NaN64GlobalDataOffset = 0;
static const unsigned NaN32GlobalDataOffset = NaN64GlobalDataOffset + sizeof(double);
static const unsigned InitialGlobalDataBytes = NaN32GlobalDataOffset + sizeof(float);
// These limits are agreed upon with other engines for consistency.
static const unsigned MaxTypes = 1000000;

View file

@ -57,25 +57,24 @@ static Atomic<uint32_t> wasmCodeAllocations(0);
static const uint32_t MaxWasmCodeAllocations = 16384;
static uint8_t*
AllocateCodeSegment(JSContext* cx, uint32_t totalLength)
AllocateCodeSegment(JSContext* cx, uint32_t codeLength)
{
if (wasmCodeAllocations >= MaxWasmCodeAllocations)
return nullptr;
// codeLength is a multiple of the system's page size, but not necessarily
// length is a multiple of the system's page size, but not necessarily
// a multiple of ExecutableCodePageSize.
totalLength = JS_ROUNDUP(totalLength, ExecutableCodePageSize);
codeLength = JS_ROUNDUP(codeLength, ExecutableCodePageSize);
void* p = AllocateExecutableMemory(totalLength, ProtectionSetting::Writable);
void* p = AllocateExecutableMemory(codeLength, ProtectionSetting::Writable);
// If the allocation failed and the embedding gives us a last-ditch attempt
// to purge all memory (which, in gecko, does a purging GC/CC/GC), do that
// then retry the allocation.
if (!p) {
JSRuntime* rt = cx->runtime();
if (rt->largeAllocationFailureCallback) {
rt->largeAllocationFailureCallback(rt->largeAllocationFailureCallbackData);
p = AllocateExecutableMemory(totalLength, ProtectionSetting::Writable);
if (OnLargeAllocationFailure) {
OnLargeAllocationFailure();
p = AllocateExecutableMemory(codeLength, ProtectionSetting::Writable);
}
}
@ -84,6 +83,8 @@ AllocateCodeSegment(JSContext* cx, uint32_t totalLength)
return nullptr;
}
cx->zone()->updateJitCodeMallocBytes(codeLength);
wasmCodeAllocations++;
return (uint8_t*)p;
}
@ -110,11 +111,6 @@ StaticallyLink(CodeSegment& cs, const LinkData& linkData, ExclusiveContext* cx)
PatchedImmPtr((void*)-1));
}
}
// These constants are logically part of the code:
*(double*)(cs.globalData() + NaN64GlobalDataOffset) = GenericNaN();
*(float*)(cs.globalData() + NaN32GlobalDataOffset) = GenericNaN();
}
static void
@ -225,22 +221,20 @@ CodeSegment::create(JSContext* cx,
HandleWasmMemoryObject memory)
{
MOZ_ASSERT(bytecode.length() % gc::SystemPageSize() == 0);
MOZ_ASSERT(linkData.globalDataLength % gc::SystemPageSize() == 0);
MOZ_ASSERT(linkData.functionCodeLength < bytecode.length());
auto cs = cx->make_unique<CodeSegment>();
if (!cs)
return nullptr;
cs->bytes_ = AllocateCodeSegment(cx, bytecode.length() + linkData.globalDataLength);
cs->bytes_ = AllocateCodeSegment(cx, bytecode.length());
if (!cs->bytes_)
return nullptr;
uint8_t* codeBase = cs->base();
cs->functionCodeLength_ = linkData.functionCodeLength;
cs->codeLength_ = bytecode.length();
cs->globalDataLength_ = linkData.globalDataLength;
cs->functionLength_ = linkData.functionCodeLength;
cs->length_ = bytecode.length();
cs->interruptCode_ = codeBase + linkData.interruptOffset;
cs->outOfBoundsCode_ = codeBase + linkData.outOfBoundsOffset;
cs->unalignedAccessCode_ = codeBase + linkData.unalignedAccessOffset;
@ -248,7 +242,7 @@ CodeSegment::create(JSContext* cx,
{
JitContext jcx(CompileRuntime::get(cx->compartment()->runtimeFromAnyThread()));
AutoFlushICache afc("CodeSegment::create");
AutoFlushICache::setRange(uintptr_t(codeBase), cs->codeLength());
AutoFlushICache::setRange(uintptr_t(codeBase), cs->length());
memcpy(codeBase, bytecode.begin(), bytecode.length());
StaticallyLink(*cs, linkData, cx);
@ -256,7 +250,7 @@ CodeSegment::create(JSContext* cx,
SpecializeToMemory(nullptr, *cs, metadata, memory->buffer());
}
if (!ExecutableAllocator::makeExecutable(codeBase, cs->codeLength())) {
if (!ExecutableAllocator::makeExecutable(codeBase, cs->length())) {
ReportOutOfMemory(cx);
return nullptr;
}
@ -275,19 +269,19 @@ CodeSegment::~CodeSegment()
MOZ_ASSERT(wasmCodeAllocations > 0);
wasmCodeAllocations--;
MOZ_ASSERT(totalLength() > 0);
MOZ_ASSERT(length() > 0);
// Match AllocateCodeSegment.
uint32_t size = JS_ROUNDUP(totalLength(), ExecutableCodePageSize);
uint32_t size = JS_ROUNDUP(length(), ExecutableCodePageSize);
DeallocateExecutableMemory(bytes_, size);
}
void
CodeSegment::onMovingGrow(uint8_t* prevMemoryBase, const Metadata& metadata, ArrayBufferObject& buffer)
{
AutoWritableJitCode awjc(base(), codeLength());
AutoWritableJitCode awjc(base(), length());
AutoFlushICache afc("CodeSegment::onMovingGrow");
AutoFlushICache::setRange(uintptr_t(base()), codeLength());
AutoFlushICache::setRange(uintptr_t(base()), length());
SpecializeToMemory(prevMemoryBase, *this, metadata, buffer);
}
@ -813,9 +807,9 @@ Code::ensureProfilingState(JSContext* cx, bool newProfilingEnabled)
profilingEnabled_ = newProfilingEnabled;
{
AutoWritableJitCode awjc(cx->runtime(), segment_->base(), segment_->codeLength());
AutoWritableJitCode awjc(segment_->base(), segment_->length());
AutoFlushICache afc("Code::ensureProfilingState");
AutoFlushICache::setRange(uintptr_t(segment_->base()), segment_->codeLength());
AutoFlushICache::setRange(uintptr_t(segment_->base()), segment_->length());
for (const CallSite& callSite : metadata_->callSites)
ToggleProfiling(*this, callSite, newProfilingEnabled);
@ -864,9 +858,9 @@ Code::adjustEnterAndLeaveFrameTrapsState(JSContext* cx, bool enabled)
if (wasEnabled == stillEnabled)
return;
AutoWritableJitCode awjc(cx->runtime(), segment_->base(), segment_->codeLength());
AutoWritableJitCode awjc(cx->runtime(), segment_->base(), segment_->length());
AutoFlushICache afc("Code::adjustEnterAndLeaveFrameTrapsState");
AutoFlushICache::setRange(uintptr_t(segment_->base()), segment_->codeLength());
AutoFlushICache::setRange(uintptr_t(segment_->base()), segment_->length());
for (const CallSite& callSite : metadata_->callSites) {
if (callSite.kind() != CallSite::EnterFrame && callSite.kind() != CallSite::LeaveFrame)
continue;
@ -881,9 +875,8 @@ Code::addSizeOfMisc(MallocSizeOf mallocSizeOf,
size_t* code,
size_t* data) const
{
*code += segment_->codeLength();
*code += segment_->length();
*data += mallocSizeOf(this) +
segment_->globalDataLength() +
metadata_->sizeOfIncludingThisIfNotSeen(mallocSizeOf, seenMetadata);
if (maybeBytecode_)

View file

@ -35,24 +35,18 @@ struct Metadata;
class FrameIterator;
// A wasm CodeSegment owns the allocated executable code for a wasm module.
// This allocation also currently includes the global data segment, which allows
// RIP-relative access to global data on some architectures, but this will
// change in the future to give global data its own allocation.
class CodeSegment;
typedef UniquePtr<CodeSegment> UniqueCodeSegment;
class CodeSegment
{
// bytes_ points to a single allocation with two contiguous ranges:
// executable machine code in the range [0, codeLength) and global data in
// the range [codeLength, codeLength + globalDataLength). The range
// [0, functionCodeLength) is the subrange of [0, codeLength) which contains
// function code.
// bytes_ points to a single allocation of executable machine code in
// the range [0, length_). The range [0, functionLength_) is
// the subrange of [0, length_) which contains function code.
uint8_t* bytes_;
uint32_t functionCodeLength_;
uint32_t codeLength_;
uint32_t globalDataLength_;
uint32_t functionLength_;
uint32_t length_;
// These are pointers into code for stubs used for asynchronous
// signal-handler control-flow transfer.
@ -80,10 +74,7 @@ class CodeSegment
~CodeSegment();
uint8_t* base() const { return bytes_; }
uint8_t* globalData() const { return bytes_ + codeLength_; }
uint32_t codeLength() const { return codeLength_; }
uint32_t globalDataLength() const { return globalDataLength_; }
uint32_t totalLength() const { return codeLength_ + globalDataLength_; }
uint32_t length() const { return length_; }
uint8_t* interruptCode() const { return interruptCode_; }
uint8_t* outOfBoundsCode() const { return outOfBoundsCode_; }
@ -96,10 +87,10 @@ class CodeSegment
// enter/exit.
bool containsFunctionPC(const void* pc) const {
return pc >= base() && pc < (base() + functionCodeLength_);
return pc >= base() && pc < (base() + functionLength_);
}
bool containsCodePC(const void* pc) const {
return pc >= base() && pc < (base() + codeLength_);
return pc >= base() && pc < (base() + length_);
}
// onMovingGrow must be called if the memory passed to 'create' performs a

View file

@ -196,7 +196,7 @@ ModuleGenerator::init(UniqueModuleEnvironment env, const CompileArgs& args,
{
env_ = Move(env);
linkData_.globalDataLength = AlignBytes(InitialGlobalDataBytes, sizeof(void*));
linkData_.globalDataLength = 0;
alwaysBaseline_ = args.alwaysBaseline;
debugEnabled_ = args.debugEnabled;
@ -661,31 +661,6 @@ ModuleGenerator::finishLinkData(Bytes& code)
if (!linkData_.internalLinks.append(inLink))
return false;
}
#if defined(JS_CODEGEN_X86)
// Global data accesses in x86 need to be patched with the absolute
// address of the global. Globals are allocated sequentially after the
// code section so we can just use an InternalLink.
for (GlobalAccess a : masm_.globalAccesses()) {
LinkData::InternalLink inLink(LinkData::InternalLink::RawPointer);
inLink.patchAtOffset = masm_.labelToPatchOffset(a.patchAt);
inLink.targetOffset = code.length() + a.globalDataOffset;
if (!linkData_.internalLinks.append(inLink))
return false;
}
#elif defined(JS_CODEGEN_X64)
// Global data accesses on x64 use rip-relative addressing and thus we can
// patch here, now that we know the final codeLength.
for (GlobalAccess a : masm_.globalAccesses()) {
void* from = code.begin() + a.patchAt.offset();
void* to = code.end() + a.globalDataOffset;
X86Encoding::SetRel32(from, to);
}
#else
// Global access is performed using the GlobalReg and requires no patching.
MOZ_ASSERT(masm_.globalAccesses().length() == 0);
#endif
return true;
}

View file

@ -106,22 +106,19 @@ js::wasm::ShutDownInstanceStaticData()
const void**
Instance::addressOfSigId(const SigIdDesc& sigId) const
{
MOZ_ASSERT(sigId.globalDataOffset() >= InitialGlobalDataBytes);
return (const void**)(codeSegment().globalData() + sigId.globalDataOffset());
return (const void**)(globalSegment().globalData() + sigId.globalDataOffset());
}
FuncImportTls&
Instance::funcImportTls(const FuncImport& fi)
{
MOZ_ASSERT(fi.tlsDataOffset() >= InitialGlobalDataBytes);
return *(FuncImportTls*)(codeSegment().globalData() + fi.tlsDataOffset());
return *(FuncImportTls*)(globalSegment().globalData() + fi.tlsDataOffset());
}
TableTls&
Instance::tableTls(const TableDesc& td) const
{
MOZ_ASSERT(td.globalDataOffset >= InitialGlobalDataBytes);
return *(TableTls*)(codeSegment().globalData() + td.globalDataOffset);
return *(TableTls*)(globalSegment().globalData() + td.globalDataOffset);
}
bool
@ -293,7 +290,7 @@ Instance::growMemory_i32(Instance* instance, uint32_t delta)
uint32_t ret = WasmMemoryObject::grow(memory, delta, cx);
// If there has been a moving grow, this Instance should have been notified.
MOZ_RELEASE_ASSERT(instance->tlsData_.memoryBase ==
MOZ_RELEASE_ASSERT(instance->tlsData()->memoryBase ==
instance->memory_->buffer().dataPointerEither());
return ret;
@ -310,6 +307,7 @@ Instance::currentMemory_i32(Instance* instance)
Instance::Instance(JSContext* cx,
Handle<WasmInstanceObject*> object,
UniqueCode code,
UniqueGlobalSegment globals,
HandleWasmMemoryObject memory,
SharedTableVector&& tables,
Handle<FunctionVector> funcImports,
@ -317,6 +315,7 @@ Instance::Instance(JSContext* cx,
: compartment_(cx->compartment()),
object_(object),
code_(Move(code)),
globals_(Move(globals)),
memory_(memory),
tables_(Move(tables)),
enterFrameTrapsEnabled_(false)
@ -324,11 +323,11 @@ Instance::Instance(JSContext* cx,
MOZ_ASSERT(funcImports.length() == metadata().funcImports.length());
MOZ_ASSERT(tables_.length() == metadata().tables.length());
tlsData_.cx = cx;
tlsData_.instance = this;
tlsData_.globalData = code_->segment().globalData();
tlsData_.memoryBase = memory ? memory->buffer().dataPointerEither().unwrap() : nullptr;
tlsData_.stackLimit = *(void**)cx->stackLimitAddressForJitCode(StackForUntrustedScript);
tlsData()->cx = cx;
tlsData()->instance = this;
tlsData()->globalData = globals_->globalData();
tlsData()->memoryBase = memory ? memory->buffer().dataPointerEither().unwrap() : nullptr;
tlsData()->stackLimit = *(void**)cx->stackLimitAddressForJitCode(JS::StackForUntrustedScript);
for (size_t i = 0; i < metadata().funcImports.length(); i++) {
HandleFunction f = funcImports[i];
@ -338,12 +337,12 @@ Instance::Instance(JSContext* cx,
WasmInstanceObject* calleeInstanceObj = ExportedFunctionToInstanceObject(f);
const CodeRange& codeRange = calleeInstanceObj->getExportedFunctionCodeRange(f);
Instance& calleeInstance = calleeInstanceObj->instance();
import.tls = &calleeInstance.tlsData_;
import.tls = calleeInstance.tlsData();
import.code = calleeInstance.codeSegment().base() + codeRange.funcNonProfilingEntry();
import.baselineScript = nullptr;
import.obj = calleeInstanceObj;
} else {
import.tls = &tlsData_;
import.tls = tlsData();
import.code = codeBase() + fi.interpExitCodeOffset();
import.baselineScript = nullptr;
import.obj = f;
@ -357,7 +356,7 @@ Instance::Instance(JSContext* cx,
table.base = tables_[i]->base();
}
uint8_t* globalData = code_->segment().globalData();
uint8_t* globalData = globals_->globalData();
for (size_t i = 0; i < metadata().globals.length(); i++) {
const GlobalDesc& global = metadata().globals[i];
@ -497,7 +496,7 @@ SharedMem<uint8_t*>
Instance::memoryBase() const
{
MOZ_ASSERT(metadata().usesMemory());
MOZ_ASSERT(tlsData_.memoryBase == memory_->buffer().dataPointerEither());
MOZ_ASSERT(tlsData()->memoryBase == memory_->buffer().dataPointerEither());
return memory_->buffer().dataPointerEither();
}
@ -523,7 +522,7 @@ bool
Instance::callExport(JSContext* cx, uint32_t funcIndex, CallArgs args)
{
// If there has been a moving grow, this Instance should have been notified.
MOZ_RELEASE_ASSERT(!memory_ || tlsData_.memoryBase == memory_->buffer().dataPointerEither());
MOZ_RELEASE_ASSERT(!memory_ || tlsData()->memoryBase == memory_->buffer().dataPointerEither());
if (!cx->compartment()->wasm.ensureProfilingState(cx))
return false;
@ -590,7 +589,7 @@ Instance::callExport(JSContext* cx, uint32_t funcIndex, CallArgs args)
// Call the per-exported-function trampoline created by GenerateEntry.
auto funcPtr = JS_DATA_TO_FUNC_PTR(ExportFuncPtr, codeBase() + func.entryOffset());
if (!CALL_GENERATED_2(funcPtr, exportArgs.begin(), &tlsData_))
if (!CALL_GENERATED_2(funcPtr, exportArgs.begin(), tlsData()))
return false;
}
@ -657,7 +656,7 @@ Instance::onMovingGrowMemory(uint8_t* prevMemoryBase)
{
MOZ_ASSERT(!isAsmJS());
ArrayBufferObject& buffer = memory_->buffer().as<ArrayBufferObject>();
tlsData_.memoryBase = buffer.dataPointer();
tlsData()->memoryBase = buffer.dataPointer();
code_->segment().onMovingGrow(prevMemoryBase, metadata(), buffer);
}
@ -753,10 +752,48 @@ Instance::addSizeOfMisc(MallocSizeOf mallocSizeOf,
size_t* code,
size_t* data) const
{
*data += mallocSizeOf(this);
*data += mallocSizeOf(this) + globals_->sizeOfMisc(mallocSizeOf);
code_->addSizeOfMisc(mallocSizeOf, seenMetadata, seenBytes, code, data);
for (const SharedTable& table : tables_)
*data += table->sizeOfIncludingThisIfNotSeen(mallocSizeOf, seenTables);
}
/* static */ UniqueGlobalSegment
GlobalSegment::create(uint32_t globalDataLength)
{
MOZ_ASSERT(globalDataLength % gc::SystemPageSize() == 0);
auto gs = MakeUnique<GlobalSegment>();
if (!gs)
return nullptr;
TlsData* tlsData =
reinterpret_cast<TlsData*>(js_calloc(offsetof(TlsData, globalArea) + globalDataLength));
if (!tlsData)
return nullptr;
#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
// We will emit SIMD memory accesses that require 16-byte alignment.
MOZ_RELEASE_ASSERT((uintptr_t(tlsData) % 16) == 0);
#endif
gs->tlsData_ = tlsData;
gs->globalDataLength_ = globalDataLength;
return gs;
}
GlobalSegment::~GlobalSegment()
{
js_free(tlsData_);
}
size_t
GlobalSegment::sizeOfMisc(MallocSizeOf mallocSizeOf) const
{
// Note, once the GlobalSegment is shared among instances, we will have to
// take that sharing into account.
return mallocSizeOf(this) + mallocSizeOf(tlsData_);
}

View file

@ -25,6 +25,35 @@
namespace js {
namespace wasm {
// A wasm GlobalSegment owns the allocated global data for a wasm module. A
// module may be compiled multiple times (at multiple tiers) but the compiled
// representations share the same GlobalSegment.
class GlobalSegment
{
uint32_t globalDataLength_;
TlsData* tlsData_;
GlobalSegment(const GlobalSegment&) = delete;
GlobalSegment(GlobalSegment&&) = delete;
void operator=(const GlobalSegment&) = delete;
void operator=(GlobalSegment&&) = delete;
public:
static UniquePtr<GlobalSegment> create(uint32_t globalDataLength);
GlobalSegment() { PodZero(this); }
~GlobalSegment();
TlsData* tlsData() const { return tlsData_; }
uint8_t* globalData() const { return (uint8_t*)&tlsData_->globalArea; }
uint32_t globalDataLength() const { return globalDataLength_; }
size_t sizeOfMisc(MallocSizeOf mallocSizeOf) const;
};
typedef UniquePtr<GlobalSegment> UniqueGlobalSegment;
// Instance represents a wasm instance and provides all the support for runtime
// execution of code in the instance. Instances share various immutable data
// structures with the Module from which they were instantiated and other
@ -37,9 +66,9 @@ class Instance
JSCompartment* const compartment_;
ReadBarrieredWasmInstanceObject object_;
const UniqueCode code_;
const UniqueGlobalSegment globals_;
GCPtrWasmMemoryObject memory_;
SharedTableVector tables_;
TlsData tlsData_;
bool enterFrameTrapsEnabled_;
// Internal helpers:
@ -66,6 +95,7 @@ class Instance
Instance(JSContext* cx,
HandleWasmInstanceObject object,
UniqueCode code,
UniqueGlobalSegment globals,
HandleWasmMemoryObject memory,
SharedTableVector&& tables,
Handle<FunctionVector> funcImports,
@ -74,11 +104,12 @@ class Instance
bool init(JSContext* cx);
void trace(JSTracer* trc);
JSContext* cx() const { return tlsData_.cx; }
JSContext* cx() const { return tlsData()->cx; }
JSCompartment* compartment() const { return compartment_; }
Code& code() { return *code_; }
const Code& code() const { return *code_; }
const CodeSegment& codeSegment() const { return code_->segment(); }
const GlobalSegment& globalSegment() const { return *globals_; }
uint8_t* codeBase() const { return code_->segment().base(); }
const Metadata& metadata() const { return code_->metadata(); }
bool isAsmJS() const { return metadata().isAsmJS(); }
@ -87,7 +118,7 @@ class Instance
size_t memoryLength() const;
size_t memoryMappedSize() const;
bool memoryAccessInGuardRegion(uint8_t* addr, unsigned numBytes) const;
TlsData& tlsData() { return tlsData_; }
TlsData* tlsData() const { return globals_->tlsData(); }
// This method returns a pointer to the GC object that owns this Instance.
// Instances may be reached via weak edges (e.g., Compartment::instances_)

View file

@ -635,7 +635,7 @@ class FunctionCompiler
if (inDeadCode())
return nullptr;
auto* load = MWasmLoadGlobalVar::New(alloc(), type, globalDataOffset, isConst);
auto* load = MWasmLoadGlobalVar::New(alloc(), type, globalDataOffset, isConst, tlsPointer_);
curBlock_->add(load);
return load;
}
@ -644,7 +644,7 @@ class FunctionCompiler
{
if (inDeadCode())
return;
curBlock_->add(MWasmStoreGlobalVar::New(alloc(), globalDataOffset, v));
curBlock_->add(MWasmStoreGlobalVar::New(alloc(), globalDataOffset, v, tlsPointer_));
}
void addInterruptCheck()

View file

@ -919,6 +919,7 @@ WasmInstanceObject::trace(JSTracer* trc, JSObject* obj)
/* static */ WasmInstanceObject*
WasmInstanceObject::create(JSContext* cx,
UniqueCode code,
UniqueGlobalSegment globals,
HandleWasmMemoryObject memory,
SharedTableVector&& tables,
Handle<FunctionVector> funcImports,
@ -953,6 +954,7 @@ WasmInstanceObject::create(JSContext* cx,
auto* instance = cx->new_<Instance>(cx,
obj,
Move(code),
Move(globals),
memory,
Move(tables),
funcImports,

View file

@ -184,6 +184,7 @@ class WasmInstanceObject : public NativeObject
static WasmInstanceObject* create(JSContext* cx,
UniquePtr<wasm::Code> code,
UniquePtr<wasm::GlobalSegment> globals,
HandleWasmMemoryObject memory,
Vector<RefPtr<wasm::Table>, 0, SystemAllocPolicy>&& tables,
Handle<FunctionVector> funcImports,

View file

@ -896,6 +896,12 @@ Module::instantiate(JSContext* cx,
return false;
}
auto globalSegment = GlobalSegment::create(linkData_.globalDataLength);
if (!globalSegment) {
ReportOutOfMemory(cx);
return false;
}
auto code = cx->make_unique<Code>(Move(codeSegment), *metadata_, maybeBytecode);
if (!code) {
ReportOutOfMemory(cx);
@ -904,6 +910,7 @@ Module::instantiate(JSContext* cx,
instance.set(WasmInstanceObject::create(cx,
Move(code),
Move(globalSegment),
memory,
Move(tables),
funcImports,

View file

@ -570,11 +570,6 @@ wasm::GenerateImportInterpExit(MacroAssembler& masm, const FuncImport& fi, uint3
defined(JS_CODEGEN_LOONGARCH64)
MOZ_ASSERT(NonVolatileRegs.has(HeapReg));
#endif
#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || \
defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) || \
defined(JS_CODEGEN_LOONGARCH64)
MOZ_ASSERT(NonVolatileRegs.has(GlobalReg));
#endif
GenerateExitEpilogue(masm, framePushed, ExitReason::ImportInterp, &offsets);

View file

@ -117,7 +117,7 @@ Table::set(uint32_t index, void* code, Instance& instance)
JSObject::writeBarrierPre(elem.tls->instance->objectUnbarriered());
elem.code = code;
elem.tls = &instance.tlsData();
elem.tls = instance.tlsData();
MOZ_ASSERT(elem.tls->instance->objectUnbarriered()->isTenured(), "no writeBarrierPost");
} else {

View file

@ -19,6 +19,7 @@
#ifndef wasm_types_h
#define wasm_types_h
#include "mozilla/Alignment.h"
#include "mozilla/EnumeratedArray.h"
#include "mozilla/HashFunctions.h"
#include "mozilla/Maybe.h"
@ -86,6 +87,7 @@ typedef Vector<uint8_t, 0, SystemAllocPolicy> Bytes;
class Code;
class CodeRange;
class GlobalSegment;
class Memory;
class Module;
class Instance;
@ -996,8 +998,15 @@ struct TlsData
// stack pointer in the prologue of functions that allocate stack space. See
// `CodeGenerator::generateWasm`.
void* stackLimit;
// The globalArea must be the last field. Globals for the module start here
// and are inline in this structure. 16-byte alignment is required for SIMD
// data.
MOZ_ALIGNED_DECL(char globalArea, 16);
};
static_assert(offsetof(TlsData, globalArea) % 16 == 0, "aligned");
typedef int32_t (*ExportFuncPtr)(ExportArg* args, TlsData* tls);
// FuncImportTls describes the region of wasm global memory allocated in the