352e408b0e
Add codegen support for up to 4GiB memories in Liftoff code. This CL also adds three new mjsunit tests that stress large WASM memories (1, 2, and 4 GiB) and checks that accesses near these boundaries properly generate traps. Note there is still some trickiness around the setting of: 1.) the flag --wasm-max-mem-pages 2.) wasm-limits.h kSpecMaxWasmMemoryPages = 65536 3.) wasm-limits.h kV8MaxWasmMemoryPages = 32767 In particular, the allocation of memories is still limited to 3.) and the runtime flag can only lower this limit. The above means that the tests for 2GiB and 4GiB memories will silently OOM by design until 3.) is changed (though they currently pass with manual testing). I argue it is better to include these tests up front, since they will immediately trigger if their memory allocation succeeds. Therefore the plan is to lift the restriction on 3.) after removing all other other internal V8 limitations including array buffers and views. R=clemensh@chromium.org CC=mstarzinger@chromium.org BUG=v8:7881 Change-Id: I3205ac2daf5c9a84364c670a2c3ef2258e5649f6 Reviewed-on: https://chromium-review.googlesource.com/1151309 Commit-Queue: Ben Titzer <titzer@chromium.org> Reviewed-by: Clemens Hammacher <clemensh@chromium.org> Cr-Commit-Position: refs/heads/master@{#54754}
98 lines
3.4 KiB
JavaScript
98 lines
3.4 KiB
JavaScript
// Copyright 2018 the V8 project authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
load('test/mjsunit/wasm/wasm-constants.js');
|
|
load('test/mjsunit/wasm/wasm-module-builder.js');
|
|
|
|
const k1MiB = 1 * 1024 * 1024;
|
|
const k1GiB = 1 * 1024 * 1024 * 1024;
|
|
const k2GiB = 2 * k1GiB;
|
|
const k3GiB = 3 * k1GiB;
|
|
const k4GiB = 4 * k1GiB;
|
|
const kMaxMemory = k4GiB;
|
|
|
|
// Indexes (and offsets) used to systematically probe the memory.
|
|
const indexes = (() => {
|
|
const a = k1GiB, b = k2GiB, c = k3GiB, d = k4GiB;
|
|
return [
|
|
0, 1, 2, 3, 4, 5, 7, 8, 9, // near 0
|
|
a-8, a-4, a+0, a+1, a+2, a+3, a+4, a+5, a+7, a+8, a+9, // near 1GiB
|
|
b-8, b-4, b+0, b+1, b+2, b+3, b+4, b+5, b+7, b+8, b+9, // near 2GiB
|
|
c-8, c-4, c+0, c+1, c+2, c+3, c+4, c+5, c+7, c+8, c+9, // near 3GiB
|
|
d-9, d-8, d-7, d-5, d-4, d-3, d-2, d-1 // near 4GiB
|
|
];
|
|
})();
|
|
|
|
(function Test() {
|
|
var memory;
|
|
|
|
function BuildAccessors(type, load_opcode, store_opcode, offset) {
|
|
builder = new WasmModuleBuilder();
|
|
builder.addImportedMemory("i", "mem");
|
|
const h = 0x80;
|
|
const m = 0x7f;
|
|
let offset_bytes = [h|((offset >>> 0) & m), // LEB encoding of offset
|
|
h|((offset >>> 7) & m),
|
|
h|((offset >>> 14) & m),
|
|
h|((offset >>> 21) & m),
|
|
0|((offset >>> 28) & m)];
|
|
builder.addFunction("load", makeSig([kWasmI32], [type]))
|
|
.addBody([ // --
|
|
kExprGetLocal, 0, // --
|
|
load_opcode, 0, ...offset_bytes, // --
|
|
]) // --
|
|
.exportFunc();
|
|
builder.addFunction("store", makeSig([kWasmI32, type], []))
|
|
.addBody([ // --
|
|
kExprGetLocal, 0, // --
|
|
kExprGetLocal, 1, // --
|
|
store_opcode, 0, ...offset_bytes, // --
|
|
]) // --
|
|
.exportFunc();
|
|
let i = builder.instantiate({i: {mem: memory}});
|
|
return {offset: offset, load: i.exports.load, store: i.exports.store};
|
|
}
|
|
|
|
function probe(a, size, offset, f) {
|
|
print(`size=${size} offset=${offset}`);
|
|
for (let i of indexes) {
|
|
let oob = (i + size + offset) > kMaxMemory;
|
|
if (oob) {
|
|
// print(` ${i} + ${offset} OOB`);
|
|
assertThrows(() => a.store(i, f(i)));
|
|
assertThrows(() => a.load(i));
|
|
} else {
|
|
// print(` ${i} = ${f(i)}`);
|
|
a.store(i, f(i));
|
|
assertEquals(f(i), a.load(i));
|
|
}
|
|
}
|
|
}
|
|
|
|
try {
|
|
let kPages = kMaxMemory / kPageSize;
|
|
memory = new WebAssembly.Memory({initial: kPages, maximum: kPages});
|
|
} catch (e) {
|
|
print("OOM: sorry, best effort max memory size test.");
|
|
return;
|
|
}
|
|
|
|
assertEquals(kMaxMemory, memory.buffer.byteLength);
|
|
|
|
for (let offset of indexes) {
|
|
let a = BuildAccessors(kWasmI32, kExprI32LoadMem, kExprI32StoreMem, offset);
|
|
probe(a, 4, offset, i => (0xaabbccee ^ ((i >> 11) * 0x110005)) | 0);
|
|
}
|
|
|
|
for (let offset of indexes) {
|
|
let a = BuildAccessors(kWasmI32, kExprI32LoadMem8U, kExprI32StoreMem8, offset);
|
|
probe(a, 1, offset, i => (0xee ^ ((i >> 11) * 0x05)) & 0xFF);
|
|
}
|
|
|
|
for (let offset of indexes) {
|
|
let a = BuildAccessors(kWasmF64, kExprF64LoadMem, kExprF64StoreMem, offset);
|
|
probe(a, 8, offset, i => 0xaabbccee ^ ((i >> 11) * 0x110005));
|
|
}
|
|
})();
|