20b892b5a0
There were a few places that still checked against the limit for initial memory size rather than the limit for memory size after growth (which was recently separated from the former). Bug: v8:7881 Change-Id: Id17d86e2f7a5dfa4f1dd35153b0cefc01f72ed33 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2078574 Commit-Queue: Jakob Kummerow <jkummerow@chromium.org> Reviewed-by: Andreas Haas <ahaas@chromium.org> Cr-Commit-Position: refs/heads/master@{#66496}
473 lines
16 KiB
JavaScript
473 lines
16 KiB
JavaScript
// Copyright 2016 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.
|
|
|
|
// Flags: --expose-wasm
|
|
|
|
load("test/mjsunit/wasm/wasm-module-builder.js");
|
|
|
|
// V8 internal memory size limit.
|
|
var kV8MaxPages = 65536;
|
|
|
|
(function TestOne() {
|
|
print("TestOne");
|
|
let memory = new WebAssembly.Memory({initial: 1});
|
|
assertEquals(kPageSize, memory.buffer.byteLength);
|
|
let i32 = new Int32Array(memory.buffer);
|
|
let builder = new WasmModuleBuilder();
|
|
builder.addImportedMemory("mod", "mine");
|
|
builder.addFunction("main", kSig_i_v)
|
|
.addBody([
|
|
kExprI32Const, 0,
|
|
kExprI32LoadMem, 0, 0])
|
|
.exportAs("main");
|
|
|
|
let main = builder.instantiate({mod: {mine: memory}}).exports.main;
|
|
assertEquals(0, main());
|
|
|
|
i32[0] = 993377;
|
|
|
|
assertEquals(993377, main());
|
|
})();
|
|
|
|
(function TestIdentity() {
|
|
print("TestIdentity");
|
|
let memory = new WebAssembly.Memory({initial: 1});
|
|
let i32 = new Int32Array(memory.buffer);
|
|
let builder = new WasmModuleBuilder();
|
|
builder.addImportedMemory("dad", "garg");
|
|
builder.exportMemoryAs("daggle");
|
|
|
|
let instance = builder.instantiate({dad: {garg: memory}});
|
|
assertSame(memory, instance.exports.daggle);
|
|
})();
|
|
|
|
(function TestImportExport() {
|
|
print("TestImportExport");
|
|
var i1;
|
|
{
|
|
let builder = new WasmModuleBuilder();
|
|
builder.addMemory(1, 1, false);
|
|
builder.exportMemoryAs("exported_mem");
|
|
builder.addFunction("foo", kSig_i_i)
|
|
.addBody([
|
|
kExprLocalGet, 0,
|
|
kExprI32LoadMem, 0, 0])
|
|
.exportAs("foo");
|
|
i1 = builder.instantiate();
|
|
}
|
|
|
|
var i2;
|
|
{
|
|
let builder = new WasmModuleBuilder();
|
|
builder.addImportedMemory("fil", "imported_mem");
|
|
builder.addFunction("bar", kSig_i_i)
|
|
.addBody([
|
|
kExprLocalGet, 0,
|
|
kExprI32LoadMem, 0, 0])
|
|
.exportAs("bar");
|
|
i2 = builder.instantiate({fil: {imported_mem: i1.exports.exported_mem}});
|
|
}
|
|
|
|
let i32 = new Int32Array(i1.exports.exported_mem.buffer);
|
|
|
|
for (var i = 0; i < 1e11; i = i * 3 + 5) {
|
|
for (var j = 0; j < 10; j++) {
|
|
var val = i + 99077 + j;
|
|
i32[j] = val;
|
|
assertEquals(val | 0, i1.exports.foo(j * 4));
|
|
assertEquals(val | 0, i2.exports.bar(j * 4));
|
|
}
|
|
}
|
|
})();
|
|
|
|
(function ValidateBoundsCheck() {
|
|
print("ValidateBoundsCheck");
|
|
let memory = new WebAssembly.Memory({initial: 1, maximum: 5});
|
|
assertEquals(kPageSize, memory.buffer.byteLength);
|
|
let i32 = new Int32Array(memory.buffer);
|
|
let builder = new WasmModuleBuilder();
|
|
builder.addImportedMemory("gaz", "mine");
|
|
builder.addFunction("load", kSig_i_i)
|
|
.addBody([kExprLocalGet, 0, kExprI32LoadMem, 0, 0])
|
|
.exportFunc();
|
|
builder.addFunction("store", kSig_i_ii)
|
|
.addBody([kExprLocalGet, 0, kExprLocalGet, 1, kExprI32StoreMem, 0, 0,
|
|
kExprLocalGet, 1])
|
|
.exportFunc();
|
|
var offset;
|
|
let instance = builder.instantiate({gaz: {mine: memory}});
|
|
function load() { return instance.exports.load(offset); }
|
|
function store(value) { return instance.exports.store(offset, value); }
|
|
|
|
for (offset = 0; offset < kPageSize - 3; offset+=4) {
|
|
store(offset);
|
|
}
|
|
for (offset = 0; offset < kPageSize - 3; offset+=4) {
|
|
assertEquals(offset, load());
|
|
}
|
|
for (offset = kPageSize - 3; offset < kPageSize + 4; offset++) {
|
|
assertTraps(kTrapMemOutOfBounds, load);
|
|
}
|
|
})();
|
|
|
|
(function TestMemoryGrowMaxDesc() {
|
|
print("MaximumDescriptor");
|
|
let memory = new WebAssembly.Memory({initial: 1, maximum: 5});
|
|
assertEquals(kPageSize, memory.buffer.byteLength);
|
|
let i32 = new Int32Array(memory.buffer);
|
|
let builder = new WasmModuleBuilder();
|
|
builder.addImportedMemory("mine", "dog", 0, 20);
|
|
builder.addFunction("load", kSig_i_i)
|
|
.addBody([kExprLocalGet, 0, kExprI32LoadMem, 0, 0])
|
|
.exportFunc();
|
|
builder.addFunction("store", kSig_i_ii)
|
|
.addBody([kExprLocalGet, 0, kExprLocalGet, 1, kExprI32StoreMem, 0, 0,
|
|
kExprLocalGet, 1])
|
|
.exportFunc();
|
|
var offset;
|
|
let instance = builder.instantiate({mine: {dog: memory}});
|
|
function load() { return instance.exports.load(offset); }
|
|
function store(value) { return instance.exports.store(offset, value); }
|
|
|
|
for (var i = 1; i < 5; i++) {
|
|
for (offset = (i - 1) * kPageSize; offset < i * kPageSize - 3; offset+=4) {
|
|
store(offset * 2);
|
|
}
|
|
assertEquals(i, memory.grow(1));
|
|
assertEquals((i + 1) * kPageSize, memory.buffer.byteLength);
|
|
}
|
|
for (offset = 4 * kPageSize; offset < 5 * kPageSize - 3; offset+=4) {
|
|
store(offset * 2);
|
|
}
|
|
for (offset = 0; offset < 5 * kPageSize - 3; offset+=4) {
|
|
assertEquals(offset * 2, load());
|
|
}
|
|
for (offset = 5 * kPageSize; offset < 5 * kPageSize + 4; offset++) {
|
|
assertThrows(load);
|
|
}
|
|
assertThrows(() => memory.grow(1));
|
|
})();
|
|
|
|
(function TestMemoryGrowZeroInitialMemory() {
|
|
print("ZeroInitialMemory");
|
|
let memory = new WebAssembly.Memory({initial: 0});
|
|
assertEquals(0, memory.buffer.byteLength);
|
|
let i32 = new Int32Array(memory.buffer);
|
|
let builder = new WasmModuleBuilder();
|
|
builder.addImportedMemory("mine", "fro");
|
|
builder.addFunction("load", kSig_i_i)
|
|
.addBody([kExprLocalGet, 0, kExprI32LoadMem, 0, 0])
|
|
.exportFunc();
|
|
builder.addFunction("store", kSig_i_ii)
|
|
.addBody([kExprLocalGet, 0, kExprLocalGet, 1, kExprI32StoreMem, 0, 0,
|
|
kExprLocalGet, 1])
|
|
.exportFunc();
|
|
var offset;
|
|
let instance = builder.instantiate({mine: {fro: memory}});
|
|
function load() { return instance.exports.load(offset); }
|
|
function store(value) { return instance.exports.store(offset, value); }
|
|
|
|
for (var i = 1; i < 5; i++) {
|
|
assertEquals(i - 1, memory.grow(1));
|
|
assertEquals(i * kPageSize, memory.buffer.byteLength);
|
|
for (offset = (i - 1) * kPageSize; offset < i * kPageSize - 3; offset++) {
|
|
store(offset * 2);
|
|
}
|
|
}
|
|
for (offset = 5 * kPageSize; offset < 5 * kPageSize + 4; offset++) {
|
|
assertThrows(load);
|
|
}
|
|
assertThrows(() => memory.grow(kV8MaxPages - 3));
|
|
})();
|
|
|
|
(function ImportedMemoryBufferLength() {
|
|
print("ImportedMemoryBufferLength");
|
|
let memory = new WebAssembly.Memory({initial: 2, maximum: 10});
|
|
assertEquals(2*kPageSize, memory.buffer.byteLength);
|
|
let builder = new WasmModuleBuilder();
|
|
builder.addFunction("grow", kSig_i_i)
|
|
.addBody([kExprLocalGet, 0, kExprMemoryGrow, kMemoryZero])
|
|
.exportFunc();
|
|
builder.addImportedMemory("cat", "mine");
|
|
let instance = builder.instantiate({cat: {mine: memory}});
|
|
function grow(pages) { return instance.exports.grow(pages); }
|
|
assertEquals(2, grow(3));
|
|
assertEquals(5*kPageSize, memory.buffer.byteLength);
|
|
assertEquals(5, grow(5));
|
|
assertEquals(10*kPageSize, memory.buffer.byteLength);
|
|
assertThrows(() => memory.grow(1));
|
|
})();
|
|
|
|
(function TestMemoryGrowExportedMaximum() {
|
|
print("TestMemoryGrowExportedMaximum");
|
|
let initial_size = 1, maximum_size = 10;
|
|
var exp_instance;
|
|
{
|
|
let builder = new WasmModuleBuilder();
|
|
builder.addMemory(initial_size, maximum_size, true);
|
|
builder.exportMemoryAs("exported_mem");
|
|
exp_instance = builder.instantiate();
|
|
}
|
|
var instance;
|
|
{
|
|
var builder = new WasmModuleBuilder();
|
|
builder.addImportedMemory("fur", "imported_mem");
|
|
builder.addFunction("mem_size", kSig_i_v)
|
|
.addBody([kExprMemorySize, kMemoryZero])
|
|
.exportFunc();
|
|
builder.addFunction("grow", kSig_i_i)
|
|
.addBody([kExprLocalGet, 0, kExprMemoryGrow, kMemoryZero])
|
|
.exportFunc();
|
|
instance = builder.instantiate({fur: {
|
|
imported_mem: exp_instance.exports.exported_mem}});
|
|
}
|
|
for (var i = initial_size; i < maximum_size; i++) {
|
|
assertEquals(i, instance.exports.grow(1));
|
|
assertEquals((i+1), instance.exports.mem_size());
|
|
}
|
|
assertEquals(-1, instance.exports.grow(1));
|
|
})();
|
|
|
|
(function TestMemoryGrowWebAssemblyInstances() {
|
|
print("TestMemoryGrowWebAssemblyInstances");
|
|
let memory = new WebAssembly.Memory({initial: 1, maximum: 15});
|
|
var builder = new WasmModuleBuilder();
|
|
builder.addImportedMemory("lit", "imported_mem");
|
|
builder.addFunction("mem_size", kSig_i_v)
|
|
.addBody([kExprMemorySize, kMemoryZero])
|
|
.exportAs("mem_size");
|
|
builder.addFunction("grow", kSig_i_i)
|
|
.addBody([kExprLocalGet, 0, kExprMemoryGrow, kMemoryZero])
|
|
.exportFunc();
|
|
var module = new WebAssembly.Module(builder.toBuffer());
|
|
var instances = [];
|
|
for (var i = 0; i < 6; i++) {
|
|
instances.push(new WebAssembly.Instance(module, {lit: {imported_mem: memory}}));
|
|
}
|
|
function verify_mem_size(expected_pages) {
|
|
assertEquals(expected_pages*kPageSize,
|
|
memory.buffer.byteLength);
|
|
for (var i = 0; i < 6; i++) {
|
|
assertEquals(expected_pages, instances[i].exports.mem_size());
|
|
}
|
|
}
|
|
|
|
// Verify initial memory size
|
|
verify_mem_size(1);
|
|
|
|
// Verify memory size with interleaving calls to Memory.grow,
|
|
// MemoryGrow opcode.
|
|
var current_mem_size = 1;
|
|
for (var i = 0; i < 5; i++) {
|
|
function grow(pages) { return instances[i].exports.grow(pages); }
|
|
assertEquals(current_mem_size, memory.grow(1));
|
|
verify_mem_size(++current_mem_size);
|
|
assertEquals(current_mem_size, instances[i].exports.grow(1));
|
|
verify_mem_size(++current_mem_size);
|
|
}
|
|
|
|
assertThrows(() => memory.grow(5));
|
|
})();
|
|
|
|
(function TestImportedMemoryGrowMultipleInstances() {
|
|
print("TestImportMemoryMultipleInstances");
|
|
let memory = new WebAssembly.Memory({initial: 5, maximum: 100});
|
|
var builder = new WasmModuleBuilder();
|
|
builder.addImportedMemory("nob", "imported_mem");
|
|
builder.addFunction("mem_size", kSig_i_v)
|
|
.addBody([kExprMemorySize, kMemoryZero])
|
|
.exportFunc();
|
|
builder.addFunction("grow", kSig_i_i)
|
|
.addBody([kExprLocalGet, 0, kExprMemoryGrow, kMemoryZero])
|
|
.exportFunc();
|
|
var instances = [];
|
|
for (var i = 0; i < 5; i++) {
|
|
instances.push(builder.instantiate({nob: {imported_mem: memory}}));
|
|
}
|
|
function grow_instance_0(pages) { return instances[0].exports.grow(pages); }
|
|
function grow_instance_1(pages) { return instances[1].exports.grow(pages); }
|
|
function grow_instance_2(pages) { return instances[2].exports.grow(pages); }
|
|
function grow_instance_3(pages) { return instances[3].exports.grow(pages); }
|
|
function grow_instance_4(pages) { return instances[4].exports.grow(pages); }
|
|
|
|
function verify_mem_size(expected_pages) {
|
|
assertEquals(expected_pages*kPageSize, memory.buffer.byteLength);
|
|
for (var i = 0; i < 5; i++) {
|
|
assertEquals(expected_pages, instances[i].exports.mem_size());
|
|
}
|
|
}
|
|
|
|
// Verify initial memory size
|
|
verify_mem_size(5);
|
|
|
|
// Grow instance memory and buffer memory out of order and verify memory is
|
|
// updated correctly.
|
|
assertEquals(5, grow_instance_0(7));
|
|
verify_mem_size(12);
|
|
|
|
assertEquals(12, memory.grow(4));
|
|
verify_mem_size(16);
|
|
|
|
assertEquals(16, grow_instance_4(1));
|
|
verify_mem_size(17);
|
|
|
|
assertEquals(17, grow_instance_1(6));
|
|
verify_mem_size(23);
|
|
|
|
assertEquals(23, grow_instance_3(2));
|
|
verify_mem_size(25);
|
|
|
|
assertEquals(25, memory.grow(10));
|
|
verify_mem_size(35);
|
|
|
|
assertEquals(35, grow_instance_2(15));
|
|
verify_mem_size(50);
|
|
assertThrows(() => memory.grow(51));
|
|
})();
|
|
|
|
(function TestExportImportedMemoryGrowMultipleInstances() {
|
|
print("TestExportImportedMemoryGrowMultipleInstances");
|
|
var instance;
|
|
{
|
|
let builder = new WasmModuleBuilder();
|
|
builder.addMemory(1, 11, true);
|
|
builder.exportMemoryAs("exported_mem");
|
|
builder.addFunction("mem_size", kSig_i_v)
|
|
.addBody([kExprMemorySize, kMemoryZero])
|
|
.exportFunc();
|
|
instance = builder.instantiate();
|
|
}
|
|
var builder = new WasmModuleBuilder();
|
|
builder.addImportedMemory("doo", "imported_mem");
|
|
builder.addFunction("mem_size", kSig_i_v)
|
|
.addBody([kExprMemorySize, kMemoryZero])
|
|
.exportFunc();
|
|
builder.addFunction("grow", kSig_i_i)
|
|
.addBody([kExprLocalGet, 0, kExprMemoryGrow, kMemoryZero])
|
|
.exportFunc();
|
|
var instances = [];
|
|
for (var i = 0; i < 10; i++) {
|
|
instances.push(builder.instantiate({
|
|
doo: {imported_mem: instance.exports.exported_mem}}));
|
|
}
|
|
function verify_mem_size(expected_pages) {
|
|
for (var i = 0; i < 10; i++) {
|
|
assertEquals(expected_pages, instances[i].exports.mem_size());
|
|
}
|
|
}
|
|
var current_mem_size = 1;
|
|
for (var i = 0; i < 10; i++) {
|
|
function grow(pages) { return instances[i].exports.grow(pages); }
|
|
assertEquals(current_mem_size, instances[i].exports.grow(1));
|
|
verify_mem_size(++current_mem_size);
|
|
}
|
|
for (var i = 0; i < 10; i++) {
|
|
assertEquals(-1, instances[i].exports.grow(1));
|
|
verify_mem_size(current_mem_size);
|
|
}
|
|
})();
|
|
|
|
(function TestExportImportedMemoryGrowPastV8Maximum() {
|
|
// The spec maximum is higher than the internal V8 maximum. This test only
|
|
// checks that grow_memory does not grow past the internally defined maximum
|
|
// to reflect the current implementation even when the memory is exported.
|
|
print("TestExportImportedMemoryGrowPastV8Maximum");
|
|
var instance_1, instance_2;
|
|
{
|
|
let builder = new WasmModuleBuilder();
|
|
builder.addMemory(1, kSpecMaxPages, true);
|
|
builder.exportMemoryAs("exported_mem");
|
|
builder.addFunction("grow", kSig_i_i)
|
|
.addBody([kExprLocalGet, 0, kExprMemoryGrow, kMemoryZero])
|
|
.exportFunc();
|
|
instance_1 = builder.instantiate();
|
|
}
|
|
{
|
|
let builder = new WasmModuleBuilder();
|
|
builder.addImportedMemory("doo", "imported_mem");
|
|
builder.addFunction("grow", kSig_i_i)
|
|
.addBody([kExprLocalGet, 0, kExprMemoryGrow, kMemoryZero])
|
|
.exportFunc();
|
|
instance_2 = builder.instantiate({
|
|
doo: {imported_mem: instance_1.exports.exported_mem}});
|
|
}
|
|
assertEquals(1, instance_1.exports.grow(20));
|
|
assertEquals(21, instance_2.exports.grow(20));
|
|
assertEquals(-1, instance_1.exports.grow(kV8MaxPages - 40));
|
|
assertEquals(-1, instance_2.exports.grow(kV8MaxPages - 40));
|
|
})();
|
|
|
|
(function TestExportGrow() {
|
|
print("TestExportGrow");
|
|
let builder = new WasmModuleBuilder();
|
|
builder.addMemory(1, 5, true);
|
|
builder.exportMemoryAs("exported_mem");
|
|
builder.addFunction("mem_size", kSig_i_v)
|
|
.addBody([kExprMemorySize, kMemoryZero])
|
|
.exportFunc();
|
|
builder.addFunction("grow", kSig_i_i)
|
|
.addBody([kExprLocalGet, 0, kExprMemoryGrow, kMemoryZero])
|
|
.exportFunc();
|
|
instance = builder.instantiate();
|
|
assertEquals(kPageSize, instance.exports.exported_mem.buffer.byteLength);
|
|
assertEquals(1, instance.exports.grow(2));
|
|
assertEquals(3, instance.exports.mem_size());
|
|
assertEquals(3*kPageSize, instance.exports.exported_mem.buffer.byteLength);
|
|
})();
|
|
|
|
(function TestImportTooLarge() {
|
|
print("TestImportTooLarge");
|
|
let builder = new WasmModuleBuilder();
|
|
builder.addImportedMemory("m", "m", 1, 2);
|
|
|
|
// initial size is too large
|
|
assertThrows(() => builder.instantiate({m: {m: new WebAssembly.Memory({initial: 3, maximum: 3})}}));
|
|
|
|
// maximum size is too large
|
|
assertThrows(() => builder.instantiate({m: {m: new WebAssembly.Memory({initial: 1, maximum: 4})}}));
|
|
|
|
// no maximum
|
|
assertThrows(() => builder.instantiate({m: {m: new WebAssembly.Memory({initial: 1})}}));
|
|
})();
|
|
|
|
(function TestMemoryGrowDetachBuffer() {
|
|
print("TestMemoryGrowDetachBuffer");
|
|
let memory = new WebAssembly.Memory({initial: 1, maximum: 5});
|
|
var builder = new WasmModuleBuilder();
|
|
builder.addImportedMemory("m", "imported_mem");
|
|
let instance = builder.instantiate({m: {imported_mem: memory}});
|
|
let buffer = memory.buffer;
|
|
assertEquals(kPageSize, buffer.byteLength);
|
|
assertEquals(1, memory.grow(2));
|
|
assertTrue(buffer !== memory.buffer);
|
|
assertEquals(0, buffer.byteLength);
|
|
assertEquals(3*kPageSize, memory.buffer.byteLength);
|
|
})();
|
|
|
|
(function TestInitialMemorySharedModule() {
|
|
print("TestInitialMemorySharedModule");
|
|
var builder = new WasmModuleBuilder();
|
|
builder.addImportedMemory("m", "imported_mem");
|
|
builder.addFunction('f', kSig_i_v)
|
|
.addBody([
|
|
kExprI32Const, 0x1d, // --
|
|
kExprI32Const, 0x20, // --
|
|
kExprI32StoreMem, 0, 0, // --
|
|
kExprI32Const, 0x1d, // --
|
|
kExprI32LoadMem, 0, 0, // --
|
|
])
|
|
.exportFunc();
|
|
|
|
// First instance load/store success
|
|
var module = new WebAssembly.Module(builder.toBuffer());
|
|
let memory1= new WebAssembly.Memory({initial: 1, maximum: 20});
|
|
let instance1 = new WebAssembly.Instance(module, {m: {imported_mem: memory1}});
|
|
assertEquals(0x20, instance1.exports.f());
|
|
|
|
// Second instance should trap as it has no initial memory
|
|
let memory2= new WebAssembly.Memory({initial: 0, maximum: 2});
|
|
let instance2 = new WebAssembly.Instance(module, {m: {imported_mem: memory2}});
|
|
assertTraps(kTrapMemOutOfBounds, () => instance2.exports.f());
|
|
})();
|