Backed out 8 changesets (bug 1615434, bug 1642940) for SM bustages on limits.js . CLOSED TREE

Backed out changeset b4a816af3fdf (bug 1642940)
Backed out changeset 5660e8f9b0f5 (bug 1642940)
Backed out changeset 3f3f63e1156b (bug 1642940)
Backed out changeset 068ffb754356 (bug 1615434)
Backed out changeset daa7bbbfe721 (bug 1642940)
Backed out changeset 4312510d2a52 (bug 1642940)
Backed out changeset 0fde857a66d9 (bug 1642940)
Backed out changeset 534530689a10 (bug 1642940)
This commit is contained in:
Narcis Beleuzu 2020-06-25 08:16:03 +03:00
Родитель 948e22eaaf
Коммит d5f6bcfb75
23 изменённых файлов: 185 добавлений и 426 удалений

Просмотреть файл

@ -119,6 +119,18 @@ wasmEvalText('(module (import "a" "" (func $foo (result f64))))', {a:{"":()=>{}}
wasmValidateText('(module (memory 0))');
wasmValidateText('(module (memory 1))');
wasmValidateText('(module (memory 16384))');
wasmFailValidateText('(module (memory 16385))', /initial memory size too big/);
wasmEvalText('(module (memory 0 65536))')
wasmFailValidateText('(module (memory 0 65537))', /maximum memory size too big/);
// May OOM, but must not crash:
try {
wasmEvalText('(module (memory 16384))');
} catch (e) {
assertEq(String(e).indexOf("out of memory") !== -1, true);
}
var buf = wasmEvalText('(module (memory 1) (export "memory" (memory 0)))').exports.memory.buffer;
assertEq(buf instanceof ArrayBuffer, true);

Просмотреть файл

@ -23,6 +23,27 @@ function assertSegmentFitError(f) {
}
}
// Memory size consistency and internal limits.
assertErrorMessage(() => new Memory({initial:2, maximum:1}), RangeError, /bad Memory maximum size/);
try {
new Memory({initial:16384});
} catch(e) {
assertEq(String(e).indexOf("out of memory") !== -1, true);
}
assertErrorMessage(() => new Memory({initial: 16385}), RangeError, /bad Memory initial size/);
new Memory({initial: 0, maximum: 65536});
assertErrorMessage(() => new Memory({initial: 0, maximum: 65537}), RangeError, /bad Memory maximum size/);
// Table size consistency and internal limits.
assertErrorMessage(() => new Table({initial:2, maximum:1, element:"funcref"}), RangeError, /bad Table maximum size/);
new Table({ initial: 10000000, element:"funcref" });
assertErrorMessage(() => new Table({initial:10000001, element:"funcref"}), RangeError, /bad Table initial size/);
new Table({ initial: 0, maximum: 10000000, element:"funcref" });
assertErrorMessage(() => new Table({initial:0, maximum: 10000001, element:"funcref"}), RangeError, /bad Table maximum size/);
const m1 = new Module(wasmTextToBinary('(module (import "foo" "bar" (func)) (import "baz" "quux" (func)))'));
assertErrorMessage(() => new Instance(m1), TypeError, /second argument must be an object/);
assertErrorMessage(() => new Instance(m1, {foo:null}), TypeError, /import object field 'foo' is not an Object/);

Просмотреть файл

@ -1,228 +0,0 @@
// Tests of limits of memory and table types
const PageSize = 65536;
const MemoryMaxValid = 65536;
const MemoryMaxRuntime = Math.floor(0x7fff_ffff / PageSize);
const TableMaxValid = 0xffff_ffff;
const TableMaxRuntime = 10_000_000;
// Test that a memory type is valid within a module
function testMemoryValidate(initial, maximum, shared) {
wasmValidateText(`(module
(memory ${initial} ${maximum || ''} ${shared ? 'shared' : ''})
)`);
}
testMemoryValidate(0, undefined, false);
testMemoryValidate(1, undefined, false);
testMemoryValidate(0, 1, false);
testMemoryValidate(0, 1, true);
testMemoryValidate(1, 1, false);
testMemoryValidate(1, 1, true);
testMemoryValidate(MemoryMaxValid, undefined, false);
testMemoryValidate(MemoryMaxValid, MemoryMaxValid, false);
testMemoryValidate(MemoryMaxValid, MemoryMaxValid, true);
// Test that a memory type is not valid within a module
function testMemoryFailValidate(initial, maximum, shared, pattern) {
wasmFailValidateText(`(module
(memory ${initial} ${maximum || ''} ${shared ? 'shared' : ''})
)`, pattern);
}
testMemoryFailValidate(2, 1, false, /size minimum must not be greater than maximum/);
testMemoryFailValidate(1, undefined, true, /maximum length required for shared memory/);
testMemoryFailValidate(MemoryMaxValid + 1, undefined, false, /initial memory size too big/);
testMemoryFailValidate(MemoryMaxValid, MemoryMaxValid + 1, false, /maximum memory size too big/);
testMemoryFailValidate(MemoryMaxValid, MemoryMaxValid + 1, true, /maximum memory size too big/);
// Test that a memory type is invalid for constructing a WebAssembly.Memory
function testMemoryFailConstruct(initial, maximum, shared, pattern) {
assertErrorMessage(() => new WebAssembly.Memory({
initial,
maximum,
shared
}), RangeError, pattern);
}
testMemoryFailConstruct(MemoryMaxValid + 1, undefined, false, /bad Memory initial size/);
testMemoryFailConstruct(0, MemoryMaxValid + 1, false, /bad Memory maximum size/);
testMemoryFailConstruct(MemoryMaxValid + 1, undefined, true, /bad Memory initial size/);
testMemoryFailConstruct(0, MemoryMaxValid + 1, true, /bad Memory maximum size/);
// Test that a memory type can be instantiated within a module or constructed
// with a WebAssembly.Memory
function testMemoryCreate(initial, maximum, shared) {
// May OOM, but must not fail to validate
try {
wasmEvalText(`(module
(memory ${initial} ${maximum || ''} ${shared ? 'shared' : ''})
)`);
} catch (e) {
assertEq(String(e).indexOf("out of memory") !== -1, true, `${e}`);
}
try {
new WebAssembly.Memory({initial, maximum, shared});
} catch (e) {
assertEq(String(e).indexOf("out of memory") !== -1, true, `${e}`);
}
}
testMemoryCreate(0, undefined, false);
testMemoryCreate(1, undefined, false);
testMemoryCreate(0, 1, false);
testMemoryCreate(0, 1, true);
testMemoryCreate(1, 1, false);
testMemoryCreate(1, 1, true);
testMemoryCreate(MemoryMaxRuntime, undefined, false);
testMemoryCreate(MemoryMaxRuntime, MemoryMaxValid, false);
testMemoryCreate(MemoryMaxRuntime, MemoryMaxValid, true);
// Test that a memory type cannot be instantiated within a module or constructed
// with a WebAssembly.Memory
function testMemoryFailCreate(initial, maximum, shared, pattern) {
assertErrorMessage(() => wasmEvalText(`(module
(memory ${initial} ${maximum || ''} ${shared ? 'shared' : ''})
)`), WebAssembly.RuntimeError, pattern);
assertErrorMessage(() => new WebAssembly.Memory({
initial,
maximum,
shared
}), WebAssembly.RuntimeError, pattern);
}
testMemoryFailCreate(MemoryMaxRuntime + 1, undefined, false, /too many memory pages/);
testMemoryFailCreate(MemoryMaxRuntime + 1, MemoryMaxValid, false, /too many memory pages/);
testMemoryFailCreate(MemoryMaxRuntime + 1, MemoryMaxValid, true, /too many memory pages/);
// Test that a memory type cannot be grown from initial to a target due to an
// implementation limit
function testMemoryFailGrow(initial, maximum, target, shared) {
let {run} = wasmEvalText(`(module
(memory ${initial} ${maximum || ''} ${shared ? 'shared' : ''})
(func (export "run") (result i32)
i32.const ${target - initial}
memory.grow
)
)`).exports;
assertEq(run(), -1, 'failed to grow');
let mem = new WebAssembly.Memory({
initial,
maximum,
shared
});
assertErrorMessage(() => mem.grow(target - initial), RangeError, /failed to grow memory/);
}
testMemoryFailGrow(1, undefined, MemoryMaxRuntime + 1, false);
testMemoryFailGrow(1, MemoryMaxValid, MemoryMaxRuntime + 1, false);
testMemoryFailGrow(1, MemoryMaxValid, MemoryMaxRuntime + 1, true);
// Test that a table type is valid within a module
function testTableValidate(initial, maximum) {
wasmValidateText(`(module
(table ${initial} ${maximum || ''} externref)
)`);
}
testTableValidate(0, undefined);
testTableValidate(1, undefined);
testTableValidate(0, 1);
testTableValidate(1, 1);
testTableValidate(TableMaxValid, undefined);
testTableValidate(TableMaxValid, TableMaxValid);
// Test that a table type is not valid within a module
function testTableFailValidate(initial, maximum, pattern) {
wasmFailValidateText(`(module
(table ${initial} ${maximum || ''} externref)
)`, pattern);
}
testTableFailValidate(2, 1, /size minimum must not be greater than maximum/);
// The maximum valid table value is equivalent to the maximum encodable limit
// value, so we cannot test too large of a table limit in a module.
assertEq(TableMaxValid + 1 > 0xffffffff, true);
// Test that a table type is invalid for constructing a WebAssembly.Table
function testTableFailConstruct(initial, maximum, pattern) {
assertErrorMessage(() => new WebAssembly.Table({
initial,
maximum,
element: 'externref',
}), TypeError, pattern);
}
testTableFailConstruct(TableMaxValid + 1, undefined, /bad Table initial size/);
testTableFailConstruct(0, TableMaxValid + 1, /bad Table maximum size/);
// Test that a table type can be instantiated within a module or constructed
// with a WebAssembly.Table
function testTableCreate(initial, maximum) {
// May OOM, but must not fail to validate
try {
wasmEvalText(`(module
(table ${initial} ${maximum || ''} externref)
)`);
} catch (e) {
assertEq(String(e).indexOf("out of table") !== -1, true, `${e}`);
}
try {
new WebAssembly.Table({
initial,
maximum,
element: 'externref',
});
} catch (e) {
assertEq(String(e).indexOf("out of table") !== -1, true, `${e}`);
}
}
testTableCreate(0, undefined);
testTableCreate(1, undefined);
testTableCreate(0, 1);
testTableCreate(1, 1);
testTableCreate(TableMaxRuntime, undefined);
testTableCreate(TableMaxRuntime, TableMaxValid);
// Test that a table type cannot be instantiated within a module or constructed
// with a WebAssembly.Table
function testTableFailCreate(initial, maximum, pattern) {
assertErrorMessage(() => wasmEvalText(`(module
(table ${initial} ${maximum || ''} externref)
)`), WebAssembly.RuntimeError, pattern);
assertErrorMessage(() => new WebAssembly.Table({
initial,
maximum,
element: 'externref',
}), WebAssembly.RuntimeError, pattern);
}
testTableFailCreate(TableMaxRuntime + 1, undefined, /too many table elements/);
testTableFailCreate(TableMaxRuntime + 1, TableMaxValid, /too many table elements/);
// Test that a table type cannot be grown from initial to a target due to an
// implementation limit
function testTableFailGrow(initial, maximum, target) {
let {run} = wasmEvalText(`(module
(table ${initial} ${maximum || ''} externref)
(func (export "run") (result i32)
ref.null extern
i32.const ${target - initial}
table.grow
)
)`).exports;
assertEq(run(), -1, 'failed to grow');
let tab = new WebAssembly.Table({
initial,
maximum,
element: 'externref',
});
assertErrorMessage(() => tab.grow(target - initial), RangeError, /failed to grow table/);
}
testTableFailGrow(1, undefined, TableMaxRuntime + 1);
testTableFailGrow(1, TableMaxValid, TableMaxRuntime + 1);

Просмотреть файл

@ -38,7 +38,7 @@ class MIRGenerator final {
const CompileInfo* outerInfo,
const OptimizationInfo* optimizationInfo);
void initMinWasmHeapLength(uint64_t init) { minWasmHeapLength_ = init; }
void initMinWasmHeapLength(uint32_t init) { minWasmHeapLength_ = init; }
TempAllocator& alloc() { return *alloc_; }
MIRGraph& graph() { return *graph_; }
@ -115,7 +115,7 @@ class MIRGenerator final {
MOZ_ASSERT(wasmMaxStackArgBytes_ == 0);
wasmMaxStackArgBytes_ = n;
}
uint64_t minWasmHeapLength() const { return minWasmHeapLength_; }
uint32_t minWasmHeapLength() const { return minWasmHeapLength_; }
void setNeedsOverrecursedCheck() { needsOverrecursedCheck_ = true; }
bool needsOverrecursedCheck() const { return needsOverrecursedCheck_; }
@ -147,7 +147,7 @@ class MIRGenerator final {
bool stringsCanBeInNursery_;
bool bigIntsCanBeInNursery_;
uint64_t minWasmHeapLength_;
uint32_t minWasmHeapLength_;
#if defined(JS_ION_PERF)
WasmPerfSpewer wasmPerfSpewer_;

Просмотреть файл

@ -50,7 +50,7 @@ bool jit::EliminateBoundsChecks(MIRGenerator* mir, MIRGraph& graph) {
if (addr->isConstant() &&
addr->toConstant()->type() == MIRType::Int32 &&
uint64_t(addr->toConstant()->toInt32()) <
uint32_t(addr->toConstant()->toInt32()) <
mir->minWasmHeapLength()) {
bc->setRedundant();
if (JitOptions.spectreIndexMasking) {

Просмотреть файл

@ -412,8 +412,6 @@ MSG_DEF(JSMSG_WASM_OUT_OF_BOUNDS, 0, JSEXN_WASMRUNTIMEERROR, "index out of
MSG_DEF(JSMSG_WASM_UNALIGNED_ACCESS, 0, JSEXN_WASMRUNTIMEERROR, "unaligned memory access")
MSG_DEF(JSMSG_WASM_WAKE_OVERFLOW, 0, JSEXN_WASMRUNTIMEERROR, "too many woken agents")
MSG_DEF(JSMSG_WASM_DEREF_NULL, 0, JSEXN_WASMRUNTIMEERROR, "dereferencing null pointer")
MSG_DEF(JSMSG_WASM_MEM_IMP_LIMIT, 0, JSEXN_WASMRUNTIMEERROR, "too many memory pages")
MSG_DEF(JSMSG_WASM_TABLE_IMP_LIMIT, 0, JSEXN_WASMRUNTIMEERROR, "too many table elements")
MSG_DEF(JSMSG_WASM_BAD_RANGE , 2, JSEXN_RANGEERR, "bad {0} {1}")
MSG_DEF(JSMSG_WASM_BAD_GROW, 1, JSEXN_RANGEERR, "failed to grow {0}")
MSG_DEF(JSMSG_WASM_TABLE_OUT_OF_BOUNDS, 0, JSEXN_WASMRUNTIMEERROR, "table index out of bounds")

Просмотреть файл

@ -598,7 +598,7 @@ MOZ_MUST_USE bool WasmArrayRawBuffer::growToSizeInPlace(uint32_t oldSize,
return true;
}
bool WasmArrayRawBuffer::extendMappedSize(uint64_t maxSize) {
bool WasmArrayRawBuffer::extendMappedSize(uint32_t maxSize) {
size_t newMappedSize = wasm::ComputeMappedSize(maxSize);
MOZ_ASSERT(mappedSize_ <= newMappedSize);
if (mappedSize_ == newMappedSize) {
@ -613,8 +613,8 @@ bool WasmArrayRawBuffer::extendMappedSize(uint64_t maxSize) {
return true;
}
void WasmArrayRawBuffer::tryGrowMaxSizeInPlace(uint64_t deltaMaxSize) {
CheckedInt<uint64_t> newMaxSize = maxSize_.value();
void WasmArrayRawBuffer::tryGrowMaxSizeInPlace(uint32_t deltaMaxSize) {
CheckedInt<uint32_t> newMaxSize = maxSize_.value();
newMaxSize += deltaMaxSize;
MOZ_ASSERT(newMaxSize.isValid());
MOZ_ASSERT(newMaxSize.value() % wasm::PageSize == 0);
@ -628,8 +628,10 @@ void WasmArrayRawBuffer::tryGrowMaxSizeInPlace(uint64_t deltaMaxSize) {
/* static */
WasmArrayRawBuffer* WasmArrayRawBuffer::Allocate(uint32_t numBytes,
const Maybe<uint64_t>& maxSize,
const Maybe<uint32_t>& maxSize,
const Maybe<size_t>& mapped) {
MOZ_RELEASE_ASSERT(numBytes <= ArrayBufferObject::MaxBufferByteLength);
size_t mappedSize = mapped.isSome()
? *mapped
: wasm::ComputeMappedSize(maxSize.valueOr(numBytes));
@ -674,11 +676,11 @@ WasmArrayRawBuffer* ArrayBufferObject::BufferContents::wasmBuffer() const {
template <typename ObjT, typename RawbufT>
static bool CreateSpecificWasmBuffer(
JSContext* cx, uint32_t initialSize, const Maybe<uint64_t>& maxSize,
JSContext* cx, uint32_t initialSize, const Maybe<uint32_t>& maxSize,
MutableHandleArrayBufferObjectMaybeShared maybeSharedObject) {
bool useHugeMemory = wasm::IsHugeMemoryEnabled();
Maybe<uint64_t> clampedMaxSize = maxSize;
Maybe<uint32_t> clampedMaxSize = maxSize;
if (clampedMaxSize) {
#ifdef JS_64BIT
// On 64-bit platforms when we aren't using huge memory, clamp
@ -687,7 +689,7 @@ static bool CreateSpecificWasmBuffer(
// wasm::PageSize == 0
if (!useHugeMemory &&
clampedMaxSize.value() >= (UINT32_MAX - wasm::PageSize)) {
uint64_t clamp = (wasm::MaxMemoryLimitField - 2) * wasm::PageSize;
uint32_t clamp = (wasm::MaxMemoryMaximumPages - 2) * wasm::PageSize;
MOZ_ASSERT(clamp < UINT32_MAX);
MOZ_ASSERT(initialSize <= clamp);
clampedMaxSize = Some(clamp);
@ -699,10 +701,8 @@ static bool CreateSpecificWasmBuffer(
// (like UINT32_MAX) from unintentially OOMing the browser: they just
// want "a lot of memory". Maintain the invariant that
// initialSize <= clampedMaxSize.
static const uint64_t OneGiB = 1 << 30;
static_assert(wasm::HighestValidARMImmediate > OneGiB,
"computing mapped size on ARM requires clamped max size");
uint64_t clamp = std::max(OneGiB, uint64_t(initialSize));
static const uint32_t OneGiB = 1 << 30;
uint32_t clamp = std::max(OneGiB, initialSize);
clampedMaxSize = Some(std::min(clamp, *clampedMaxSize));
#endif
}
@ -735,10 +735,10 @@ static bool CreateSpecificWasmBuffer(
return false;
}
uint64_t cur = clampedMaxSize.value() / 2;
uint32_t cur = clampedMaxSize.value() / 2;
for (; cur > initialSize; cur /= 2) {
uint64_t clampedMaxSize = RoundUp(cur, wasm::PageSize);
uint32_t clampedMaxSize = RoundUp(cur, wasm::PageSize);
buffer = RawbufT::Allocate(initialSize, Some(clampedMaxSize), mappedSize);
if (buffer) {
break;
@ -806,10 +806,8 @@ bool js::CreateWasmBuffer(JSContext* cx, const wasm::Limits& memory,
MutableHandleArrayBufferObjectMaybeShared buffer) {
MOZ_ASSERT(memory.initial % wasm::PageSize == 0);
MOZ_RELEASE_ASSERT(cx->wasmHaveSignalHandlers);
MOZ_RELEASE_ASSERT(memory.initial <= ArrayBufferObject::MaxBufferByteLength);
static_assert(ArrayBufferObject::MaxBufferByteLength <= UINT32_MAX,
"wasm memory uses uint32_t and is limited by"
"MaxBufferByteLength");
MOZ_RELEASE_ASSERT((memory.initial / wasm::PageSize) <=
wasm::MaxMemoryInitialPages);
if (memory.shared == wasm::Shareable::True) {
if (!cx->realm()->creationOptions().getSharedMemoryAndAtomicsEnabled()) {
@ -819,10 +817,10 @@ bool js::CreateWasmBuffer(JSContext* cx, const wasm::Limits& memory,
}
return CreateSpecificWasmBuffer<SharedArrayBufferObject,
SharedArrayRawBuffer>(
cx, uint32_t(memory.initial), memory.maximum, buffer);
cx, memory.initial, memory.maximum, buffer);
}
return CreateSpecificWasmBuffer<ArrayBufferObject, WasmArrayRawBuffer>(
cx, uint32_t(memory.initial), memory.maximum, buffer);
cx, memory.initial, memory.maximum, buffer);
}
bool ArrayBufferObject::prepareForAsmJS() {
@ -980,11 +978,11 @@ size_t js::WasmArrayBufferMappedSize(const ArrayBufferObjectMaybeShared* buf) {
return buf->as<SharedArrayBufferObject>().wasmMappedSize();
}
Maybe<uint64_t> ArrayBufferObject::wasmMaxSize() const {
Maybe<uint32_t> ArrayBufferObject::wasmMaxSize() const {
if (isWasm()) {
return contents().wasmBuffer()->maxSize();
} else {
return Some<uint64_t>(byteLength());
return Some<uint32_t>(byteLength());
}
}
@ -1067,7 +1065,7 @@ bool ArrayBufferObject::wasmMovingGrowToSize(
}
if (wasm::ComputeMappedSize(newSize) <= oldBuf->wasmMappedSize() ||
oldBuf->contents().wasmBuffer()->extendMappedSize(uint64_t(newSize))) {
oldBuf->contents().wasmBuffer()->extendMappedSize(newSize)) {
return wasmGrowToSizeInPlace(newSize, oldBuf, newBuf, cx);
}

Просмотреть файл

@ -119,7 +119,7 @@ class ArrayBufferObjectMaybeShared : public NativeObject {
// Note: the eventual goal is to remove this from ArrayBuffer and have
// (Shared)ArrayBuffers alias memory owned by some wasm::Memory object.
mozilla::Maybe<uint64_t> wasmMaxSize() const {
mozilla::Maybe<uint32_t> wasmMaxSize() const {
return WasmArrayBufferMaxSize(this);
}
size_t wasmMappedSize() const { return WasmArrayBufferMappedSize(this); }
@ -429,7 +429,7 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared {
MOZ_MUST_USE bool prepareForAsmJS();
size_t wasmMappedSize() const;
mozilla::Maybe<uint64_t> wasmMaxSize() const;
mozilla::Maybe<uint32_t> wasmMaxSize() const;
static MOZ_MUST_USE bool wasmGrowToSizeInPlace(
uint32_t newSize, Handle<ArrayBufferObject*> oldBuf,
MutableHandle<ArrayBufferObject*> newBuf, JSContext* cx);
@ -680,12 +680,12 @@ class MutableWrappedPtrOperations<InnerViewTable, Wrapper>
};
class WasmArrayRawBuffer {
mozilla::Maybe<uint64_t> maxSize_;
mozilla::Maybe<uint32_t> maxSize_;
size_t mappedSize_; // Not including the header page
uint32_t length_;
protected:
WasmArrayRawBuffer(uint8_t* buffer, const mozilla::Maybe<uint64_t>& maxSize,
WasmArrayRawBuffer(uint8_t* buffer, const mozilla::Maybe<uint32_t>& maxSize,
size_t mappedSize, uint32_t length)
: maxSize_(maxSize), mappedSize_(mappedSize), length_(length) {
MOZ_ASSERT(buffer == dataPointer());
@ -693,7 +693,7 @@ class WasmArrayRawBuffer {
public:
static WasmArrayRawBuffer* Allocate(uint32_t numBytes,
const mozilla::Maybe<uint64_t>& maxSize,
const mozilla::Maybe<uint32_t>& maxSize,
const mozilla::Maybe<size_t>& mappedSize);
static void Release(void* mem);
@ -711,17 +711,17 @@ class WasmArrayRawBuffer {
size_t mappedSize() const { return mappedSize_; }
mozilla::Maybe<uint64_t> maxSize() const { return maxSize_; }
mozilla::Maybe<uint32_t> maxSize() const { return maxSize_; }
uint32_t byteLength() const { return length_; }
MOZ_MUST_USE bool growToSizeInPlace(uint32_t oldSize, uint32_t newSize);
MOZ_MUST_USE bool extendMappedSize(uint64_t maxSize);
MOZ_MUST_USE bool extendMappedSize(uint32_t maxSize);
// Try and grow the mapped region of memory. Does not change current size.
// Does not move memory if no space to grow.
void tryGrowMaxSizeInPlace(uint64_t deltaMaxSize);
void tryGrowMaxSizeInPlace(uint32_t deltaMaxSize);
};
} // namespace js

Просмотреть файл

@ -44,7 +44,7 @@ static size_t SharedArrayMappedSize(uint32_t length) {
// `maxSize` must be something for wasm, nothing for other cases.
SharedArrayRawBuffer* SharedArrayRawBuffer::Allocate(
uint32_t length, const Maybe<uint64_t>& maxSize,
uint32_t length, const Maybe<uint32_t>& maxSize,
const Maybe<size_t>& mappedSize) {
MOZ_RELEASE_ASSERT(length <= ArrayBufferObject::MaxBufferByteLength);
@ -54,7 +54,7 @@ SharedArrayRawBuffer* SharedArrayRawBuffer::Allocate(
}
bool preparedForWasm = maxSize.isSome();
uint64_t computedMaxSize;
uint32_t computedMaxSize;
size_t computedMappedSize;
if (preparedForWasm) {
@ -86,8 +86,8 @@ SharedArrayRawBuffer* SharedArrayRawBuffer::Allocate(
return rawbuf;
}
void SharedArrayRawBuffer::tryGrowMaxSizeInPlace(uint64_t deltaMaxSize) {
CheckedInt<uint64_t> newMaxSize = maxSize_;
void SharedArrayRawBuffer::tryGrowMaxSizeInPlace(uint32_t deltaMaxSize) {
CheckedInt<uint32_t> newMaxSize = maxSize_;
newMaxSize += deltaMaxSize;
MOZ_ASSERT(newMaxSize.isValid());
MOZ_ASSERT(newMaxSize.value() % wasm::PageSize == 0);

Просмотреть файл

@ -51,7 +51,7 @@ class SharedArrayRawBuffer {
mozilla::Atomic<uint32_t, mozilla::ReleaseAcquire> refcount_;
mozilla::Atomic<uint32_t, mozilla::SequentiallyConsistent> length_;
Mutex growLock_;
uint64_t maxSize_;
uint32_t maxSize_;
size_t mappedSize_; // Does not include the page for the header
bool preparedForWasm_;
@ -66,7 +66,7 @@ class SharedArrayRawBuffer {
}
protected:
SharedArrayRawBuffer(uint8_t* buffer, uint32_t length, uint64_t maxSize,
SharedArrayRawBuffer(uint8_t* buffer, uint32_t length, uint32_t maxSize,
size_t mappedSize, bool preparedForWasm)
: refcount_(1),
length_(length),
@ -94,7 +94,7 @@ class SharedArrayRawBuffer {
// max must be Something for wasm, Nothing for other uses
static SharedArrayRawBuffer* Allocate(
uint32_t length, const mozilla::Maybe<uint64_t>& maxSize,
uint32_t length, const mozilla::Maybe<uint32_t>& maxSize,
const mozilla::Maybe<size_t>& mappedSize);
// This may be called from multiple threads. The caller must take
@ -118,13 +118,13 @@ class SharedArrayRawBuffer {
uint32_t volatileByteLength() const { return length_; }
uint64_t maxSize() const { return maxSize_; }
uint32_t maxSize() const { return maxSize_; }
size_t mappedSize() const { return mappedSize_; }
bool isWasm() const { return preparedForWasm_; }
void tryGrowMaxSizeInPlace(uint64_t deltaMaxSize);
void tryGrowMaxSizeInPlace(uint32_t deltaMaxSize);
bool wasmGrowToSizeInPlace(const Lock&, uint32_t newLength);
@ -229,7 +229,7 @@ class SharedArrayBufferObject : public ArrayBufferObjectMaybeShared {
static SharedArrayBufferObject* createFromNewRawBuffer(
JSContext* cx, SharedArrayRawBuffer* buffer, uint32_t initialSize);
mozilla::Maybe<uint64_t> wasmMaxSize() const {
mozilla::Maybe<uint32_t> wasmMaxSize() const {
return mozilla::Some(rawBufferObject()->maxSize());
}

Просмотреть файл

@ -95,7 +95,7 @@ using mozilla::Compression::LZ4;
// ARM greater or equal to MinHeapLength
static const size_t MinHeapLength = PageSize;
static uint64_t RoundUpToNextValidAsmJSHeapLength(uint64_t length) {
static uint32_t RoundUpToNextValidAsmJSHeapLength(uint32_t length) {
if (length <= MinHeapLength) {
return MinHeapLength;
}
@ -1434,7 +1434,7 @@ class MOZ_STACK_CLASS JS_HAZ_ROOTED ModuleValidatorShared {
PropertyName* bufferArgumentName() const { return bufferArgumentName_; }
const ModuleEnvironment& env() { return env_; }
uint64_t minMemoryLength() const { return env_.minMemoryLength; }
uint32_t minMemoryLength() const { return env_.minMemoryLength; }
void initModuleFunctionName(PropertyName* name) {
MOZ_ASSERT(!moduleFunctionName_);
@ -1975,7 +1975,7 @@ class MOZ_STACK_CLASS JS_HAZ_ROOTED ModuleValidator
bool declareFuncPtrTable(FuncType&& sig, PropertyName* name,
uint32_t firstUse, uint32_t mask,
uint32_t* tableIndex) {
if (mask > MaxTableLength) {
if (mask > MaxTableInitialLength) {
return failCurrentOffset("function pointer table too big");
}
@ -1993,7 +1993,7 @@ class MOZ_STACK_CLASS JS_HAZ_ROOTED ModuleValidator
}
env_.asmJSSigToTableIndex[sigIndex] = env_.tables.length();
if (!env_.tables.emplaceBack(TableKind::AsmJS, mask + 1, Nothing())) {
if (!env_.tables.emplaceBack(TableKind::AsmJS, Limits(mask + 1))) {
return false;
}
@ -6721,13 +6721,12 @@ static bool CheckBuffer(JSContext* cx, const AsmJSMetadata& metadata,
}
buffer.set(&AsAnyArrayBuffer(bufferVal));
uint64_t memoryLength = uint64_t(buffer->byteLength());
uint32_t memoryLength = buffer->byteLength();
if (!IsValidAsmJSHeapLength(memoryLength)) {
UniqueChars msg(JS_smprintf(
"ArrayBuffer byteLength 0x%" PRIu64
" is not a valid heap length. The next "
"valid length is 0x%" PRIu64,
"ArrayBuffer byteLength 0x%x is not a valid heap length. The next "
"valid length is 0x%x",
memoryLength, RoundUpToNextValidAsmJSHeapLength(memoryLength)));
if (!msg) {
return false;
@ -6740,11 +6739,10 @@ static bool CheckBuffer(JSContext* cx, const AsmJSMetadata& metadata,
// byteLength has larger alignment.
MOZ_ASSERT((metadata.minMemoryLength - 1) <= INT32_MAX);
if (memoryLength < metadata.minMemoryLength) {
UniqueChars msg(JS_smprintf("ArrayBuffer byteLength of 0x%" PRIu64
" is less than 0x%" PRIu64 " (the "
"size implied "
"by const heap accesses).",
memoryLength, metadata.minMemoryLength));
UniqueChars msg(JS_smprintf(
"ArrayBuffer byteLength of 0x%x is less than 0x%x (the size implied "
"by const heap accesses).",
memoryLength, metadata.minMemoryLength));
if (!msg) {
return false;
}

Просмотреть файл

@ -10778,7 +10778,7 @@ RegI32 BaseCompiler::popMemoryAccess(MemoryAccessDesc* access,
uint32_t offsetGuardLimit = GetOffsetGuardLimit(env_.hugeMemoryEnabled());
uint64_t ea = uint64_t(addr) + uint64_t(access->offset());
uint64_t limit = env_.minMemoryLength + offsetGuardLimit;
uint64_t limit = uint64_t(env_.minMemoryLength) + offsetGuardLimit;
check->omitBoundsCheck = ea < limit;
check->omitAlignmentCheck = (ea & (access->byteSize() - 1)) == 0;

Просмотреть файл

@ -320,9 +320,9 @@ typedef Vector<FuncImport, 0, SystemAllocPolicy> FuncImportVector;
struct MetadataCacheablePod {
ModuleKind kind;
MemoryUsage memoryUsage;
uint64_t minMemoryLength;
uint32_t minMemoryLength;
uint32_t globalDataLength;
Maybe<uint64_t> maxMemoryLength;
Maybe<uint32_t> maxMemoryLength;
Maybe<uint32_t> startFuncIndex;
Maybe<uint32_t> nameCustomSectionIndex;
bool filenameIsURL;

Просмотреть файл

@ -840,11 +840,6 @@ enum class NameType { Module = 0, Function = 1, Local = 2 };
enum class FieldFlags { Mutable = 0x01, AllowedMask = 0x01 };
// The WebAssembly spec hard-codes the virtual page size to be 64KiB and
// requires the size of linear memory to always be a multiple of 64KiB.
static const unsigned PageSize = 64 * 1024;
// These limits are agreed upon with other engines for consistency.
static const unsigned MaxTypes = 1000000;
@ -854,10 +849,7 @@ static const unsigned MaxImports = 100000;
static const unsigned MaxExports = 100000;
static const unsigned MaxGlobals = 1000000;
static const unsigned MaxDataSegments = 100000;
static const unsigned MaxDataSegmentLengthPages = 16384;
static const unsigned MaxElemSegments = 10000000;
static const unsigned MaxElemSegmentLength = 10000000;
static const unsigned MaxTableLimitField = UINT32_MAX;
static const unsigned MaxTableLength = 10000000;
static const unsigned MaxLocals = 50000;
static const unsigned MaxParams = 1000;
@ -865,15 +857,16 @@ static const unsigned MaxParams = 1000;
// `env->funcMaxResults()` to get the correct value for a module.
static const unsigned MaxResults = 1000;
static const unsigned MaxStructFields = 1000;
static const unsigned MaxMemoryLimitField = 65536;
static const unsigned MaxMemoryPages = INT32_MAX / PageSize;
static const unsigned MaxMemoryMaximumPages = 65536;
static const unsigned MaxStringBytes = 100000;
static const unsigned MaxModuleBytes = 1024 * 1024 * 1024;
static const unsigned MaxFunctionBytes = 7654321;
// These limits pertain to our WebAssembly implementation only.
static const unsigned MaxTableInitialLength = 10000000;
static const unsigned MaxBrTableElems = 1000000;
static const unsigned MaxMemoryInitialPages = 16384;
static const unsigned MaxCodeSectionBytes = MaxModuleBytes;
static const unsigned MaxResultsForJitEntry = 1;
static const unsigned MaxResultsForJitExit = 1;

Просмотреть файл

@ -1449,10 +1449,10 @@ class FunctionCompiler {
MOZ_ASSERT(funcType.id.kind() == FuncTypeIdDescKind::None);
const TableDesc& table =
env_.tables[env_.asmJSSigToTableIndex[funcTypeIndex]];
MOZ_ASSERT(IsPowerOfTwo(table.initialLength));
MOZ_ASSERT(IsPowerOfTwo(table.limits.initial));
MConstant* mask =
MConstant::New(alloc(), Int32Value(table.initialLength - 1));
MConstant::New(alloc(), Int32Value(table.limits.initial - 1));
curBlock_->add(mask);
MBitAnd* maskedIndex = MBitAnd::New(alloc(), index, mask, MIRType::Int32);
curBlock_->add(maskedIndex);

Просмотреть файл

@ -860,8 +860,9 @@ static bool EnforceRangeU32(JSContext* cx, HandleValue v, const char* kind,
return true;
}
static bool GetLimits(JSContext* cx, HandleObject obj, uint32_t maximumField,
const char* kind, Limits* limits, Shareable allowShared) {
static bool GetLimits(JSContext* cx, HandleObject obj, uint32_t maxInitial,
uint32_t maxMaximum, const char* kind, Limits* limits,
Shareable allowShared) {
JSAtom* initialAtom = Atomize(cx, "initial", strlen("initial"));
if (!initialAtom) {
return false;
@ -873,13 +874,12 @@ static bool GetLimits(JSContext* cx, HandleObject obj, uint32_t maximumField,
return false;
}
uint32_t initial = 0;
if (!EnforceRangeU32(cx, initialVal, kind, "initial size", &initial)) {
if (!EnforceRangeU32(cx, initialVal, kind, "initial size",
&limits->initial)) {
return false;
}
limits->initial = initial;
if (limits->initial > maximumField) {
if (limits->initial > maxInitial) {
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_RANGE,
kind, "initial size");
return false;
@ -898,13 +898,13 @@ static bool GetLimits(JSContext* cx, HandleObject obj, uint32_t maximumField,
// maxVal does not have a default value.
if (!maxVal.isUndefined()) {
uint32_t maximum = 0;
if (!EnforceRangeU32(cx, maxVal, kind, "maximum size", &maximum)) {
limits->maximum.emplace();
if (!EnforceRangeU32(cx, maxVal, kind, "maximum size",
limits->maximum.ptr())) {
return false;
}
limits->maximum = Some(maximum);
if (*limits->maximum > maximumField || limits->initial > *limits->maximum) {
if (*limits->maximum > maxMaximum || limits->initial > *limits->maximum) {
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
JSMSG_WASM_BAD_RANGE, kind, "maximum size");
return false;
@ -2057,14 +2057,8 @@ bool WasmMemoryObject::construct(JSContext* cx, unsigned argc, Value* vp) {
RootedObject obj(cx, &args[0].toObject());
Limits limits;
if (!GetLimits(cx, obj, MaxMemoryLimitField, "Memory", &limits,
Shareable::True)) {
return false;
}
if (limits.initial > MaxMemoryPages) {
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
JSMSG_WASM_MEM_IMP_LIMIT);
if (!GetLimits(cx, obj, MaxMemoryInitialPages, MaxMemoryMaximumPages,
"Memory", &limits, Shareable::True)) {
return false;
}
@ -2419,8 +2413,7 @@ void WasmTableObject::trace(JSTracer* trc, JSObject* obj) {
}
/* static */
WasmTableObject* WasmTableObject::create(JSContext* cx, uint32_t initialLength,
Maybe<uint32_t> maximumLength,
WasmTableObject* WasmTableObject::create(JSContext* cx, const Limits& limits,
TableKind tableKind,
HandleObject proto) {
AutoSetNewObjectMetadata metadata(cx);
@ -2432,12 +2425,10 @@ WasmTableObject* WasmTableObject::create(JSContext* cx, uint32_t initialLength,
MOZ_ASSERT(obj->isNewborn());
TableDesc td(tableKind, initialLength, maximumLength,
/*importedOrExported=*/true);
TableDesc td(tableKind, limits, /*importedOrExported=*/true);
SharedTable table = Table::create(cx, td, obj);
if (!table) {
ReportOutOfMemory(cx);
return nullptr;
}
@ -2515,14 +2506,8 @@ bool WasmTableObject::construct(JSContext* cx, unsigned argc, Value* vp) {
}
Limits limits;
if (!GetLimits(cx, obj, MaxTableLimitField, "Table", &limits,
Shareable::False)) {
return false;
}
if (limits.initial > MaxTableLength) {
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
JSMSG_WASM_TABLE_IMP_LIMIT);
if (!GetLimits(cx, obj, MaxTableInitialLength, MaxTableLength, "Table",
&limits, Shareable::False)) {
return false;
}
@ -2535,17 +2520,8 @@ bool WasmTableObject::construct(JSContext* cx, unsigned argc, Value* vp) {
proto = GlobalObject::getOrCreatePrototype(cx, JSProto_WasmTable);
}
// The rest of the runtime expects table limits to be within a 32-bit range.
static_assert(MaxTableLimitField <= UINT32_MAX, "invariant");
uint32_t initialLength = uint32_t(limits.initial);
Maybe<uint32_t> maximumLength;
if (limits.maximum) {
maximumLength = Some(uint32_t(*limits.maximum));
}
RootedWasmTableObject table(
cx, WasmTableObject::create(cx, initialLength, maximumLength, tableKind,
proto));
cx, WasmTableObject::create(cx, limits, tableKind, proto));
if (!table) {
return false;
}

Просмотреть файл

@ -442,8 +442,7 @@ class WasmTableObject : public NativeObject {
// Note that, after creation, a WasmTableObject's table() is not initialized
// and must be initialized before use.
static WasmTableObject* create(JSContext* cx, uint32_t initialLength,
mozilla::Maybe<uint32_t> maximumLength,
static WasmTableObject* create(JSContext* cx, const wasm::Limits& limits,
wasm::TableKind tableKind, HandleObject proto);
wasm::Table& table() const;
};

Просмотреть файл

@ -684,11 +684,10 @@ bool Module::instantiateFunctions(JSContext* cx,
return true;
}
template <typename T>
static bool CheckLimits(JSContext* cx, T declaredMin,
const Maybe<T>& declaredMax, T actualLength,
const Maybe<T>& actualMax, bool isAsmJS,
const char* kind) {
static bool CheckLimits(JSContext* cx, uint32_t declaredMin,
const Maybe<uint32_t>& declaredMax,
uint32_t actualLength, const Maybe<uint32_t>& actualMax,
bool isAsmJS, const char* kind) {
if (isAsmJS) {
MOZ_ASSERT(actualLength >= declaredMin);
MOZ_ASSERT(!declaredMax);
@ -747,18 +746,17 @@ bool Module::instantiateMemory(JSContext* cx,
return true;
}
uint64_t declaredMin = metadata().minMemoryLength;
Maybe<uint64_t> declaredMax = metadata().maxMemoryLength;
uint32_t declaredMin = metadata().minMemoryLength;
Maybe<uint32_t> declaredMax = metadata().maxMemoryLength;
bool declaredShared = metadata().memoryUsage == MemoryUsage::Shared;
if (memory) {
MOZ_ASSERT_IF(metadata().isAsmJS(), memory->buffer().isPreparedForAsmJS());
MOZ_ASSERT_IF(!metadata().isAsmJS(), memory->buffer().isWasm());
if (!CheckLimits(cx, declaredMin, declaredMax,
uint64_t(memory->volatileMemoryLength()),
memory->buffer().wasmMaxSize(), metadata().isAsmJS(),
"Memory")) {
if (!CheckLimits(
cx, declaredMin, declaredMax, memory->volatileMemoryLength(),
memory->buffer().wasmMaxSize(), metadata().isAsmJS(), "Memory")) {
return false;
}
@ -768,12 +766,6 @@ bool Module::instantiateMemory(JSContext* cx,
} else {
MOZ_ASSERT(!metadata().isAsmJS());
if (declaredMin / PageSize > MaxMemoryPages) {
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
JSMSG_WASM_MEM_IMP_LIMIT);
return false;
}
RootedArrayBufferObjectMaybeShared buffer(cx);
Limits l(declaredMin, declaredMax,
declaredShared ? Shareable::True : Shareable::False);
@ -802,7 +794,7 @@ bool Module::instantiateImportedTable(JSContext* cx, const TableDesc& td,
MOZ_ASSERT(!metadata().isAsmJS());
Table& table = tableObj->table();
if (!CheckLimits(cx, td.initialLength, td.maximumLength, table.length(),
if (!CheckLimits(cx, td.limits.initial, td.limits.maximum, table.length(),
table.maximum(), metadata().isAsmJS(), "Table")) {
return false;
}
@ -823,19 +815,12 @@ bool Module::instantiateImportedTable(JSContext* cx, const TableDesc& td,
bool Module::instantiateLocalTable(JSContext* cx, const TableDesc& td,
WasmTableObjectVector* tableObjs,
SharedTableVector* tables) const {
if (td.initialLength > MaxTableLength) {
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
JSMSG_WASM_TABLE_IMP_LIMIT);
return false;
}
SharedTable table;
Rooted<WasmTableObject*> tableObj(cx);
if (td.importedOrExported) {
RootedObject proto(
cx, &cx->global()->getPrototype(JSProto_WasmTable).toObject());
tableObj.set(WasmTableObject::create(cx, td.initialLength, td.maximumLength,
td.kind, proto));
tableObj.set(WasmTableObject::create(cx, td.limits, td.kind, proto));
if (!tableObj) {
return false;
}
@ -843,7 +828,6 @@ bool Module::instantiateLocalTable(JSContext* cx, const TableDesc& td,
} else {
table = Table::create(cx, td, /* HandleWasmTableObject = */ nullptr);
if (!table) {
ReportOutOfMemory(cx);
return false;
}
}

Просмотреть файл

@ -35,8 +35,8 @@ Table::Table(JSContext* cx, const TableDesc& desc,
observers_(cx->zone()),
functions_(std::move(functions)),
kind_(desc.kind),
length_(desc.initialLength),
maximum_(desc.maximumLength) {
length_(desc.limits.initial),
maximum_(desc.limits.maximum) {
MOZ_ASSERT(repr() == TableRepr::Func);
}
@ -46,8 +46,8 @@ Table::Table(JSContext* cx, const TableDesc& desc,
observers_(cx->zone()),
objects_(std::move(objects)),
kind_(desc.kind),
length_(desc.initialLength),
maximum_(desc.maximumLength) {
length_(desc.limits.initial),
maximum_(desc.limits.maximum) {
MOZ_ASSERT(repr() == TableRepr::Ref);
}
@ -58,7 +58,7 @@ SharedTable Table::create(JSContext* cx, const TableDesc& desc,
case TableKind::FuncRef:
case TableKind::AsmJS: {
UniqueFuncRefArray functions(
cx->pod_calloc<FunctionTableElem>(desc.initialLength));
cx->pod_calloc<FunctionTableElem>(desc.limits.initial));
if (!functions) {
return nullptr;
}
@ -67,7 +67,7 @@ SharedTable Table::create(JSContext* cx, const TableDesc& desc,
}
case TableKind::AnyRef: {
TableAnyRefVector objects;
if (!objects.resize(desc.initialLength)) {
if (!objects.resize(desc.limits.initial)) {
return nullptr;
}
return SharedTable(

Просмотреть файл

@ -45,9 +45,11 @@ using mozilla::MakeEnumeratedRange;
# endif
#endif
static_assert(MaxMemoryPages ==
// More sanity checks.
static_assert(MaxMemoryInitialPages <=
ArrayBufferObject::MaxBufferByteLength / PageSize,
"invariant");
"Memory sizing constraint");
// All plausible targets must be able to do at least IEEE754 double
// loads/stores, hence the lower limit of 8. Some Intel processors support
@ -589,10 +591,8 @@ bool wasm::IsValidARMImmediate(uint32_t i) {
return valid;
}
uint64_t wasm::RoundUpToNextValidARMImmediate(uint64_t i) {
MOZ_ASSERT(i <= HighestValidARMImmediate);
static_assert(HighestValidARMImmediate == 0xff000000,
"algorithm relies on specific constant");
uint32_t wasm::RoundUpToNextValidARMImmediate(uint32_t i) {
MOZ_ASSERT(i <= 0xff000000);
if (i <= 16 * 1024 * 1024) {
i = i ? mozilla::RoundUpPow2(i) : 0;
@ -613,7 +613,7 @@ bool wasm::IsValidBoundsCheckImmediate(uint32_t i) {
#endif
}
size_t wasm::ComputeMappedSize(uint64_t maxSize) {
size_t wasm::ComputeMappedSize(uint32_t maxSize) {
MOZ_ASSERT(maxSize % PageSize == 0);
// It is the bounds-check limit, not the mapped size, that gets baked into
@ -621,9 +621,9 @@ size_t wasm::ComputeMappedSize(uint64_t maxSize) {
// *before* adding in the guard page.
#ifdef JS_CODEGEN_ARM
uint64_t boundsCheckLimit = RoundUpToNextValidARMImmediate(maxSize);
uint32_t boundsCheckLimit = RoundUpToNextValidARMImmediate(maxSize);
#else
uint64_t boundsCheckLimit = maxSize;
uint32_t boundsCheckLimit = maxSize;
#endif
MOZ_ASSERT(IsValidBoundsCheckImmediate(boundsCheckLimit));

Просмотреть файл

@ -2774,15 +2774,15 @@ bool IsRoundingFunction(SymbolicAddress callee, jit::RoundingMode* mode);
// Represents the resizable limits of memories and tables.
struct Limits {
uint64_t initial;
Maybe<uint64_t> maximum;
uint32_t initial;
Maybe<uint32_t> maximum;
// `shared` is Shareable::False for tables but may be Shareable::True for
// memories.
Shareable shared;
Limits() = default;
explicit Limits(uint64_t initial, const Maybe<uint64_t>& maximum = Nothing(),
explicit Limits(uint32_t initial, const Maybe<uint32_t>& maximum = Nothing(),
Shareable shared = Shareable::False)
: initial(initial), maximum(maximum), shared(shared) {}
};
@ -2814,17 +2814,15 @@ struct TableDesc {
TableKind kind;
bool importedOrExported;
uint32_t globalDataOffset;
uint32_t initialLength;
Maybe<uint32_t> maximumLength;
Limits limits;
TableDesc() = default;
TableDesc(TableKind kind, uint32_t initialLength,
Maybe<uint32_t> maximumLength, bool importedOrExported = false)
TableDesc(TableKind kind, const Limits& limits,
bool importedOrExported = false)
: kind(kind),
importedOrExported(importedOrExported),
globalDataOffset(UINT32_MAX),
initialLength(initialLength),
maximumLength(maximumLength) {}
limits(limits) {}
};
typedef Vector<TableDesc, 0, SystemAllocPolicy> TableDescVector;
@ -3035,7 +3033,7 @@ class CalleeDesc {
CalleeDesc c;
c.which_ = WasmTable;
c.u.table.globalDataOffset_ = desc.globalDataOffset;
c.u.table.minLength_ = desc.initialLength;
c.u.table.minLength_ = desc.limits.initial;
c.u.table.funcTypeId_ = funcTypeId;
return c;
}
@ -3092,11 +3090,14 @@ class CalleeDesc {
// Because ARM has a fixed-width instruction encoding, ARM can only express a
// limited subset of immediates (in a single instruction).
static const uint64_t HighestValidARMImmediate = 0xff000000;
extern bool IsValidARMImmediate(uint32_t i);
extern uint64_t RoundUpToNextValidARMImmediate(uint64_t i);
extern uint32_t RoundUpToNextValidARMImmediate(uint32_t i);
// The WebAssembly spec hard-codes the virtual page size to be 64KiB and
// requires the size of linear memory to always be a multiple of 64KiB.
static const unsigned PageSize = 64 * 1024;
// Bounds checks always compare the base of the memory access with the bounds
// check limit. If the memory access is unaligned, this means that, even if the
@ -3171,7 +3172,7 @@ extern bool IsValidBoundsCheckImmediate(uint32_t i);
// boundsCheckLimit = mappedSize - GuardSize
// IsValidBoundsCheckImmediate(boundsCheckLimit)
extern size_t ComputeMappedSize(uint64_t maxSize);
extern size_t ComputeMappedSize(uint32_t maxSize);
// The following thresholds were derived from a microbenchmark. If we begin to
// ship this optimization for more platforms, we will need to extend this list.

Просмотреть файл

@ -1842,11 +1842,9 @@ static bool DecodeLimits(Decoder& d, Limits* limits,
uint32_t(flags & ~uint8_t(mask)));
}
uint32_t initial;
if (!d.readVarU32(&initial)) {
if (!d.readVarU32(&limits->initial)) {
return d.fail("expected initial length");
}
limits->initial = initial;
if (flags & uint8_t(MemoryTableFlags::HasMaximum)) {
uint32_t maximum;
@ -1857,11 +1855,11 @@ static bool DecodeLimits(Decoder& d, Limits* limits,
if (limits->initial > maximum) {
return d.failf(
"memory size minimum must not be greater than maximum; "
"maximum length %" PRIu32 " is less than initial length %" PRIu64,
"maximum length %" PRIu32 " is less than initial length %" PRIu32,
maximum, limits->initial);
}
limits->maximum.emplace(uint64_t(maximum));
limits->maximum.emplace(maximum);
}
limits->shared = Shareable::False;
@ -1913,9 +1911,8 @@ static bool DecodeTableTypeAndLimits(Decoder& d, bool refTypesEnabled,
// If there's a maximum, check it is in range. The check to exclude
// initial > maximum is carried out by the DecodeLimits call above, so
// we don't repeat it here.
if (limits.initial > MaxTableLimitField ||
((limits.maximum.isSome() &&
limits.maximum.value() > MaxTableLimitField))) {
if (limits.initial > MaxTableInitialLength ||
((limits.maximum.isSome() && limits.maximum.value() > MaxTableLength))) {
return d.fail("too many table elements");
}
@ -1923,15 +1920,7 @@ static bool DecodeTableTypeAndLimits(Decoder& d, bool refTypesEnabled,
return d.fail("too many tables");
}
// The rest of the runtime expects table limits to be within a 32-bit range.
static_assert(MaxTableLimitField <= UINT32_MAX, "invariant");
uint32_t initialLength = uint32_t(limits.initial);
Maybe<uint32_t> maximumLength;
if (limits.maximum) {
maximumLength = Some(uint32_t(*limits.maximum));
}
return tables->emplaceBack(tableKind, initialLength, maximumLength);
return tables->emplaceBack(tableKind, limits);
}
static bool GlobalIsJSCompatible(Decoder& d, ValType type) {
@ -1985,12 +1974,30 @@ static bool DecodeGlobalType(Decoder& d, const TypeDefVector& types,
}
void wasm::ConvertMemoryPagesToBytes(Limits* memory) {
memory->initial *= PageSize;
CheckedInt<uint32_t> initialBytes = memory->initial;
initialBytes *= PageSize;
static_assert(MaxMemoryInitialPages < UINT16_MAX,
"multiplying by PageSize can't overflow");
MOZ_ASSERT(initialBytes.isValid(), "can't overflow by above assertion");
memory->initial = initialBytes.value();
if (!memory->maximum) {
return;
}
*memory->maximum *= PageSize;
MOZ_ASSERT(*memory->maximum <= MaxMemoryMaximumPages);
CheckedInt<uint32_t> maximumBytes = *memory->maximum;
maximumBytes *= PageSize;
// Clamp the maximum memory value to UINT32_MAX; it's not semantically
// visible since growing will fail for values greater than INT32_MAX.
memory->maximum =
Some(maximumBytes.isValid() ? maximumBytes.value() : UINT32_MAX);
MOZ_ASSERT(memory->initial <= *memory->maximum);
}
static bool DecodeMemoryLimits(Decoder& d, ModuleEnvironment* env) {
@ -2003,11 +2010,11 @@ static bool DecodeMemoryLimits(Decoder& d, ModuleEnvironment* env) {
return false;
}
if (memory.initial > MaxMemoryLimitField) {
if (memory.initial > MaxMemoryInitialPages) {
return d.fail("initial memory size too big");
}
if (memory.maximum && *memory.maximum > MaxMemoryLimitField) {
if (memory.maximum && *memory.maximum > MaxMemoryMaximumPages) {
return d.fail("maximum memory size too big");
}
@ -2736,7 +2743,7 @@ static bool DecodeElemSection(Decoder& d, ModuleEnvironment* env) {
return d.fail("expected segment size");
}
if (numElems > MaxElemSegmentLength) {
if (numElems > MaxTableInitialLength) {
return d.fail("too many table elements");
}
@ -3053,7 +3060,7 @@ static bool DecodeDataSection(Decoder& d, ModuleEnvironment* env) {
return d.fail("expected segment size");
}
if (seg.length > MaxDataSegmentLengthPages * PageSize) {
if (seg.length > MaxMemoryInitialPages * PageSize) {
return d.fail("segment size too big");
}

Просмотреть файл

@ -159,8 +159,8 @@ struct ModuleEnvironment {
// validating an asm.js module) and immutable during compilation:
Maybe<uint32_t> dataCount;
MemoryUsage memoryUsage;
uint64_t minMemoryLength;
Maybe<uint64_t> maxMemoryLength;
uint32_t minMemoryLength;
Maybe<uint32_t> maxMemoryLength;
uint32_t numStructTypes;
TypeDefVector types;
FuncTypeWithIdPtrVector funcTypes;