// 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 'use strict'; load("test/mjsunit/wasm/wasm-module-builder.js"); // Basic tests. const outOfUint32RangeValue = 1e12; const kV8MaxWasmTableSize = 10000000; function assertTableIsValid(table, length) { assertSame(WebAssembly.Table.prototype, table.__proto__); assertSame(WebAssembly.Table, table.constructor); assertTrue(table instanceof Object); assertTrue(table instanceof WebAssembly.Table); assertEquals(length, table.length); } (function TestConstructor() { assertTrue(WebAssembly.Table instanceof Function); assertSame(WebAssembly.Table, WebAssembly.Table.prototype.constructor); assertTrue(WebAssembly.Table.prototype.grow instanceof Function); assertTrue(WebAssembly.Table.prototype.get instanceof Function); assertTrue(WebAssembly.Table.prototype.set instanceof Function); let desc = Object.getOwnPropertyDescriptor(WebAssembly.Table.prototype, 'length'); assertTrue(desc.get instanceof Function); assertSame(undefined, desc.set); assertThrows(() => new WebAssembly.Table(), TypeError); assertThrows(() => new WebAssembly.Table(1), TypeError); assertThrows(() => new WebAssembly.Table(""), TypeError); assertThrows(() => new WebAssembly.Table({}), TypeError); assertThrows(() => new WebAssembly.Table({initial: 10}), TypeError); assertThrows(() => new WebAssembly.Table({element: 0, initial: 10}), TypeError); assertThrows(() => new WebAssembly.Table({element: "any", initial: 10}), TypeError); assertThrows(() => new WebAssembly.Table( {element: "anyfunc", initial: -1}), TypeError); assertThrows(() => new WebAssembly.Table( {element: "anyfunc", initial: outOfUint32RangeValue}), TypeError); assertThrows(() => new WebAssembly.Table( {element: "anyfunc", initial: 10, maximum: -1}), TypeError); assertThrows(() => new WebAssembly.Table( {element: "anyfunc", initial: 10, maximum: outOfUint32RangeValue}), TypeError); assertThrows(() => new WebAssembly.Table( {element: "anyfunc", initial: 10, maximum: 9}), RangeError); let table; table = new WebAssembly.Table({element: "anyfunc", initial: 1}); assertTableIsValid(table, 1); assertEquals(null, table.get(0)); assertEquals(undefined, table[0]); table = new WebAssembly.Table({element: "anyfunc", initial: "2"}); assertTableIsValid(table, 2); assertEquals(null, table.get(0)); assertEquals(null, table.get(1)); assertEquals(undefined, table[0]); assertEquals(undefined, table[1]); table = new WebAssembly.Table({element: "anyfunc", initial: {valueOf() { return "1" }}}); assertTableIsValid(table, 1); assertEquals(null, table.get(0)); assertEquals(undefined, table[0]); table = new WebAssembly.Table({element: "anyfunc", initial: 0, maximum: 10}); assertTableIsValid(table, 0); table = new WebAssembly.Table({element: "anyfunc", initial: 0, maximum: "10"}); assertTableIsValid(table, 0); table = new WebAssembly.Table({element: "anyfunc", initial: 0, maximum: {valueOf() { return "10" }}}); assertTableIsValid(table, 0); table = new WebAssembly.Table({element: "anyfunc", initial: 0, maximum: undefined}); assertTableIsValid(table, 0); table = new WebAssembly.Table({element: "anyfunc", initial: 0, maximum: 1000000}); assertTableIsValid(table, 0); table = new WebAssembly.Table({element: "anyfunc", initial: 0, maximum: kV8MaxWasmTableSize}); assertTableIsValid(table, 0); assertThrows( () => new WebAssembly.Table( {element: "anyfunc", initial: 0, maximum: kV8MaxWasmTableSize + 1}), RangeError, /above the upper bound/); })(); (function TestMaximumIsReadOnce() { var a = true; var desc = {element: "anyfunc", initial: 10}; Object.defineProperty(desc, 'maximum', {get: function() { if (a) { a = false; return 16; } else { // Change the return value on the second call so it throws. return -1; } }}); let table = new WebAssembly.Table(desc); assertTableIsValid(table, 10); })(); (function TestMaximumDoesHasProperty() { var hasPropertyWasCalled = false; var desc = {element: "anyfunc", initial: 10}; var proxy = new Proxy({maximum: 16}, { has: function(target, name) { hasPropertyWasCalled = true; } }); Object.setPrototypeOf(desc, proxy); let table = new WebAssembly.Table(desc); assertTableIsValid(table, 10); })(); (function TestLength() { for (let i = 0; i < 10; ++i) { let table = new WebAssembly.Table({element: "anyfunc", initial: i}); assertEquals(i, table.length); } assertThrows(() => WebAssembly.Table.prototype.length.call([]), TypeError); })(); (function TestGet() { let table = new WebAssembly.Table({element: "anyfunc", initial: 10}); for (let i = 0; i < table.length; ++i) { assertEquals(null, table.get(i)); assertEquals(null, table.get(String(i))); } for (let key of [0.4, "", []]) { assertEquals(null, table.get(key)); } for (let key of [-1, NaN, {}, () => {}]) { assertThrows(() => table.get(key), TypeError); } for (let key of [table.length, table.length * 10]) { assertThrows(() => table.get(key), RangeError); } assertThrows(() => table.get(Symbol()), TypeError); assertThrows(() => WebAssembly.Table.prototype.get.call([], 0), TypeError); })(); (function TestSet() { let builder = new WasmModuleBuilder; builder.addExport("host", builder.addImport("test", "f", kSig_v_v)); builder.addExport("wasm", builder.addFunction("", kSig_v_v).addBody([])); let {wasm, host} = builder.instantiate({test: {f() {}}}).exports; let table = new WebAssembly.Table({element: "anyfunc", initial: 10}); for (let f of [wasm, host]) { for (let i = 0; i < table.length; ++i) table.set(i, null); for (let i = 0; i < table.length; ++i) { assertSame(null, table.get(i)); assertSame(undefined, table.set(i, f)); assertSame(f, table.get(i)); assertSame(undefined, table[i]); } for (let i = 0; i < table.length; ++i) table.set(i, null); for (let i = 0; i < table.length; ++i) { assertSame(null, table.get(i)); assertSame(undefined, table.set(String(i), f)); assertSame(f, table.get(i)); assertSame(undefined, table[i]); } for (let key of [0.4, "", []]) { assertSame(undefined, table.set(0, null)); assertSame(undefined, table.set(key, f)); assertSame(f, table.get(0)); assertSame(undefined, table[key]); } for (let key of [NaN, {}, () => {}]) { assertSame(undefined, table[key]); assertThrows(() => table.set(key, f), TypeError); } assertThrows(() => table.set(-1, f), TypeError); for (let key of [table.length, table.length * 10]) { assertThrows(() => table.set(key, f), RangeError); } assertThrows(() => table.set(0), TypeError); for (let val of [undefined, 0, "", {}, [], () => {}]) { assertThrows(() => table.set(0, val), TypeError); } assertThrows(() => table.set(Symbol(), f), TypeError); assertThrows(() => WebAssembly.Table.prototype.set.call([], 0, f), TypeError); } })(); (function TestIndexing() { let builder = new WasmModuleBuilder; builder.addExport("host", builder.addImport("test", "f", kSig_v_v)); builder.addExport("wasm", builder.addFunction("", kSig_v_v).addBody([])); let {wasm, host} = builder.instantiate({test: {f() {}}}).exports; let table = new WebAssembly.Table({element: "anyfunc", initial: 10}); for (let f of [wasm, host, () => {}, 5, {}, ""]) { for (let i = 0; i < table.length; ++i) table[i] = f; for (let i = 0; i < table.length; ++i) { assertSame(null, table.get(i)); assertSame(f, table[i]); } for (let key of [NaN, {}, () => {}]) { assertSame(f, table[key] = f); assertSame(f, table[key]); assertThrows(() => table.get(key), TypeError); } for (let key of [0.4, "", []]) { assertSame(f, table[key] = f); assertSame(f, table[key]); assertSame(null, table.get(key)); } } })(); (function TestGrow() { let builder = new WasmModuleBuilder; builder.addExport("host", builder.addImport("test", "f", kSig_v_v)); builder.addExport("wasm", builder.addFunction("", kSig_v_v).addBody([])); let {wasm, host} = builder.instantiate({test: {f() {}}}).exports; function init(table) { for (let i = 0; i < 5; ++i) table.set(i, wasm); for (let i = 15; i < 20; ++i) table.set(i, host); } function check(table) { for (let i = 0; i < 5; ++i) assertSame(wasm, table.get(i)); for (let i = 6; i < 15; ++i) assertSame(null, table.get(i)); for (let i = 15; i < 20; ++i) assertSame(host, table.get(i)); for (let i = 21; i < table.length; ++i) assertSame(null, table.get(i)); } let table = new WebAssembly.Table({element: "anyfunc", initial: 20}); init(table); check(table); table.grow(0); check(table); table.grow(10); check(table); assertThrows(() => table.grow(-10), TypeError); table = new WebAssembly.Table({element: "anyfunc", initial: 20, maximum: 25}); init(table); check(table); table.grow(0); check(table); table.grow(5); check(table); table.grow(0); check(table); assertThrows(() => table.grow(1), RangeError); assertThrows(() => table.grow(-10), TypeError); assertThrows(() => WebAssembly.Table.prototype.grow.call([], 0), TypeError); table = new WebAssembly.Table( {element: "anyfunc", initial: 0, maximum: kV8MaxWasmTableSize}); table.grow(kV8MaxWasmTableSize); assertThrows(() => table.grow(1), RangeError); table = new WebAssembly.Table({element: "anyfunc", initial: 0}); table.grow({valueOf: () => {table.grow(2); return 1;}}); assertEquals(3, table.length); })();