| // 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, // -- |
| /* */ kExprGetLocal, 0, // -- |
| /* */ kExprIf, kWasmStmt, // -- |
| /* */ kExprGetLocal, 0, // -- |
| /* */ kExprI32LoadMem, 0, 0, // -- |
| /* */ kExprIf, kWasmStmt, // -- |
| /* */ kExprI32Const, 127, // -- |
| /* */ kExprReturn, // -- |
| /* */ kExprEnd, // -- |
| /* */ kExprGetLocal, 0, // -- |
| /* */ kExprI32Const, 4, // -- |
| /* */ kExprI32Sub, // -- |
| /* */ kExprSetLocal, 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); |
| |
| for (var i = 0; i < kMemSize; i++) { |
| assertEquals(0, array[i]); |
| } |
| |
| 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); |
| |
| for (var i = 0; i < kMemSize; i++) { |
| assertEquals(0, array[i]); |
| } |
| |
| 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([ |
| kExprGetLocal, 0, |
| kExprGetLocal, 1, |
| kExprI32LoadMem, 0, 0, |
| kExprI32StoreMem, 0, 0, |
| kExprGetLocal, 1, |
| kExprI32LoadMem, 0, 0, |
| ]) |
| .exportFunc(); |
| |
| var module = builder.instantiate(); |
| var offset; |
| |
| function read() { return module.exports.geti(0, offset); } |
| function write() { return module.exports.geti(offset, 0); } |
| |
| for (offset = 0; offset < 65533; offset++) { |
| assertEquals(0, read()); |
| assertEquals(0, write()); |
| } |
| |
| // 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 (offset = 65534; offset < 66536; offset++) { |
| const trap_count = %GetWasmRecoveredTrapCount(); |
| assertTraps(kTrapMemOutOfBounds, read); |
| assertTraps(kTrapMemOutOfBounds, write); |
| 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(); |
| } |