// Copyright 2015 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 --expose-gc --stress-compaction --allow-natives-syntax load("test/mjsunit/wasm/wasm-module-builder.js"); var kMemSize = 65536; function genModule(memory) { var builder = new WasmModuleBuilder(); builder.addImportedMemory("", "memory", 1); builder.exportMemoryAs("memory"); builder.addFunction("main", kSig_i_i) .addBody([ // main body: while(i) { if(mem[i]) return -1; i -= 4; } return 0; // TODO(titzer): this manual bytecode has a copy of test-run-wasm.cc /**/ kExprLoop, kWasmStmt, // -- /* */ kExprLocalGet, 0, // -- /* */ kExprIf, kWasmStmt, // -- /* */ kExprLocalGet, 0, // -- /* */ kExprI32LoadMem, 0, 0, // -- /* */ kExprIf, kWasmStmt, // -- /* */ kExprI32Const, 127, // -- /* */ kExprReturn, // -- /* */ kExprEnd, // -- /* */ kExprLocalGet, 0, // -- /* */ kExprI32Const, 4, // -- /* */ kExprI32Sub, // -- /* */ kExprLocalSet, 0, // -- /* */ kExprBr, 1, // -- /* */ kExprEnd, // -- /* */ kExprEnd, // -- /**/ kExprI32Const, 0 // -- ]) .exportFunc(); var module = builder.instantiate({"": {memory:memory}}); assertTrue(module.exports.memory instanceof WebAssembly.Memory); if (memory != null) assertEquals(memory.buffer, module.exports.memory.buffer); return module; } function testPokeMemory() { print("testPokeMemory"); var module = genModule(new WebAssembly.Memory({initial: 1})); var buffer = module.exports.memory.buffer; var main = module.exports.main; assertEquals(kMemSize, buffer.byteLength); var array = new Int8Array(buffer); assertEquals(kMemSize, array.length); assertTrue(array.every((e => e === 0))); for (var i = 0; i < 10; i++) { assertEquals(0, main(kMemSize - 4)); array[kMemSize/2 + i] = 1; assertEquals(0, main(kMemSize/2 - 4)); assertEquals(-1, main(kMemSize - 4)); array[kMemSize/2 + i] = 0; assertEquals(0, main(kMemSize - 4)); } } testPokeMemory(); function genAndGetMain(buffer) { return genModule(buffer).exports.main; // to prevent intermediates living } function testSurvivalAcrossGc() { var checker = genAndGetMain(new WebAssembly.Memory({initial: 1})); for (var i = 0; i < 3; i++) { print("gc run ", i); assertEquals(0, checker(kMemSize - 4)); gc(); } } testSurvivalAcrossGc(); testSurvivalAcrossGc(); testSurvivalAcrossGc(); testSurvivalAcrossGc(); function testPokeOuterMemory() { print("testPokeOuterMemory"); var buffer = new WebAssembly.Memory({initial: kMemSize / kPageSize}); var module = genModule(buffer); var main = module.exports.main; assertEquals(kMemSize, buffer.buffer.byteLength); var array = new Int8Array(buffer.buffer); assertEquals(kMemSize, array.length); assertTrue(array.every((e => e === 0))); for (var i = 0; i < 10; i++) { assertEquals(0, main(kMemSize - 4)); array[kMemSize/2 + i] = 1; assertEquals(0, main(kMemSize/2 - 4)); assertEquals(-1, main(kMemSize - 4)); array[kMemSize/2 + i] = 0; assertEquals(0, main(kMemSize - 4)); } } testPokeOuterMemory(); function testOuterMemorySurvivalAcrossGc() { var buffer = new WebAssembly.Memory({initial: kMemSize / kPageSize}); var checker = genAndGetMain(buffer); for (var i = 0; i < 3; i++) { print("gc run ", i); assertEquals(0, checker(kMemSize - 4)); gc(); } } testOuterMemorySurvivalAcrossGc(); testOuterMemorySurvivalAcrossGc(); testOuterMemorySurvivalAcrossGc(); testOuterMemorySurvivalAcrossGc(); function testOOBThrows() { var builder = new WasmModuleBuilder(); builder.addMemory(1, 1, true); builder.addFunction("geti", kSig_i_ii) .addBody([ kExprLocalGet, 0, kExprLocalGet, 1, kExprI32LoadMem, 0, 0, kExprI32StoreMem, 0, 0, kExprLocalGet, 1, kExprI32LoadMem, 0, 0, ]) .exportFunc(); var module = builder.instantiate(); let read = offset => module.exports.geti(0, offset); let write = offset => module.exports.geti(offset, 0); assertEquals(0, read(65532)); assertEquals(0, write(65532)); // Note that this test might be run concurrently in multiple Isolates, which // makes an exact comparison of the expected trap count unreliable. But is is // still possible to check the lower bound for the expected trap count. for (let offset = 65534; offset < 66536; offset++) { const trap_count = %GetWasmRecoveredTrapCount(); assertTraps(kTrapMemOutOfBounds, () => read(offset)); assertTraps(kTrapMemOutOfBounds, () => write(offset)); if (%IsWasmTrapHandlerEnabled()) { assertTrue(trap_count + 2 <= %GetWasmRecoveredTrapCount()); } } } testOOBThrows(); function testAddressSpaceLimit() { // 1TiB + 4 GiB, see wasm-memory.h const kMaxAddressSpace = 1 * 1024 * 1024 * 1024 * 1024 + 4 * 1024 * 1024 * 1024; const kAddressSpacePerMemory = 10 * 1024 * 1024 * 1024; let last_memory; try { let memories = []; let address_space = 0; while (address_space <= kMaxAddressSpace + 1) { last_memory = new WebAssembly.Memory({initial: 1}) memories.push(last_memory); address_space += kAddressSpacePerMemory; } } catch (e) { assertTrue(e instanceof RangeError); return; } assertUnreachable("should have reached the address space limit"); } if(%IsWasmTrapHandlerEnabled()) { testAddressSpaceLimit(); }