Diff
Modified: trunk/JSTests/ChangeLog (271302 => 271303)
--- trunk/JSTests/ChangeLog 2021-01-08 18:01:15 UTC (rev 271302)
+++ trunk/JSTests/ChangeLog 2021-01-08 18:18:06 UTC (rev 271303)
@@ -1,5 +1,23 @@
2021-01-08 Dmitry Bezhetskov <[email protected]>
+ [WASM-References] Add optional default value parameter for Table.constructor, Table.grow and Table.set
+ https://bugs.webkit.org/show_bug.cgi?id=220323
+
+ Reviewed by Yusuke Suzuki.
+
+ Add tests for Table.grow, Table.set and Table ctor with optional initializing parameter.
+ Spec: https://webassembly.github.io/reference-types/js-api/index.html#tables.
+
+ * wasm/references/table_js_api.js: Added.
+ (Pelmen):
+ (testTableGrowForExternrefTables):
+ (async testTableGrowForFuncrefTables):
+ (testTableConstructorForExternrefTables):
+ (async testTableConstructorForFuncrefTables):
+ (async testTableSetForFuncrefTables):
+
+2021-01-08 Dmitry Bezhetskov <[email protected]>
+
[WASM-References] Add linking tests
https://bugs.webkit.org/show_bug.cgi?id=220314
Added: trunk/JSTests/wasm/references/table_js_api.js (0 => 271303)
--- trunk/JSTests/wasm/references/table_js_api.js (rev 0)
+++ trunk/JSTests/wasm/references/table_js_api.js 2021-01-08 18:18:06 UTC (rev 271303)
@@ -0,0 +1,80 @@
+//@ runWebAssemblySuite("--useWebAssemblyReferences=true")
+import * as assert from '../assert.js';
+import { instantiate } from "../wabt-wrapper.js";
+
+// trivial
+function Pelmen(calories) {
+ this.calories = calories;
+}
+const calories = 100;
+
+function testTableGrowForExternrefTables() {
+ const table = new WebAssembly.Table({initial:1, maximum:10, element: "externref"});
+ table.grow(3, new Pelmen(calories));
+ assert.eq(table.get(1).calories, calories);
+ assert.eq(table.get(2).calories, calories);
+ assert.eq(table.get(3).calories, calories);
+}
+
+async function testTableGrowForFuncrefTables() {
+ const table = new WebAssembly.Table({initial:1, maximum:10, element: "funcref"});
+ const calories = 100;
+ assert.throws(() => table.grow(3, new Pelmen(calories)), Error, "WebAssembly.Table.prototype.grow expects the second argument to be null or an instance of WebAssembly.Function");
+
+ table.grow(3, null);
+ assert.eq(table.get(1), null);
+ assert.eq(table.get(2), null);
+ assert.eq(table.get(3), null);
+
+ const instance = await instantiate(`(module (func (export "foo")))`, {}, {reference_types: true});
+ table.grow(3, instance.exports.foo);
+ assert.eq(table.get(4), instance.exports.foo);
+ assert.eq(table.get(5), instance.exports.foo);
+ assert.eq(table.get(6), instance.exports.foo);
+}
+
+function testTableConstructorForExternrefTables() {
+ const table = new WebAssembly.Table({initial:3, maximum:10, element: "externref"}, new Pelmen(calories));
+ assert.eq(table.get(0).calories, calories);
+ assert.eq(table.get(1).calories, calories);
+ assert.eq(table.get(2).calories, calories);
+ assert.throws(() => table.get(3), RangeError, "WebAssembly.Table.prototype.get expects an integer less than the length of the table");
+}
+
+async function testTableConstructorForFuncrefTables() {
+ const instance = await instantiate(`(module (func (export "foo")))`, {}, {reference_types: true});
+ const table = new WebAssembly.Table({initial:3, maximum:10, element: "funcref"}, instance.exports.foo);
+ assert.eq(table.get(0), instance.exports.foo);
+ assert.eq(table.get(1), instance.exports.foo);
+ assert.eq(table.get(2), instance.exports.foo);
+
+ assert.throws(() => new WebAssembly.Table({initial:3, maximum:10, element: "funcref"}, {}), TypeError, "WebAssembly.Table.prototype.constructor expects the second argument to be null or an instance of WebAssembly.Function");
+}
+
+function testTableSetForExternrefTables() {
+ const table = new WebAssembly.Table({initial:3, maximum:10, element: "externref"}, new Pelmen(calories));
+ assert.eq(table.get(0).calories, calories);
+
+ table.set(0);
+ assert.eq(table.get(0), null);
+}
+
+async function testTableSetForFuncrefTables() {
+ const instance = await instantiate(`(module (func (export "foo")))`, {}, {reference_types: true});
+ const table = new WebAssembly.Table({initial:3, maximum:10, element: "funcref"});
+ assert.eq(table.get(0), null);
+
+ table.set(0, instance.exports.foo);
+ assert.eq(table.get(0), instance.exports.foo);
+
+ assert.throws(() => table.set(0, {}), TypeError, "WebAssembly.Table.prototype.set expects the second argument to be null or an instance of WebAssembly.Function");
+}
+
+testTableGrowForExternrefTables();
+assert.asyncTest(testTableGrowForFuncrefTables());
+
+testTableConstructorForExternrefTables();
+assert.asyncTest(testTableConstructorForFuncrefTables());
+
+testTableSetForExternrefTables();
+assert.asyncTest(testTableSetForFuncrefTables());
Modified: trunk/Source/_javascript_Core/ChangeLog (271302 => 271303)
--- trunk/Source/_javascript_Core/ChangeLog 2021-01-08 18:01:15 UTC (rev 271302)
+++ trunk/Source/_javascript_Core/ChangeLog 2021-01-08 18:18:06 UTC (rev 271303)
@@ -1,3 +1,31 @@
+2021-01-08 Dmitry Bezhetskov <[email protected]>
+
+ [WASM-References] Add optional default value parameter for Table.constructor, Table.grow and Table.set
+ https://bugs.webkit.org/show_bug.cgi?id=220323
+
+ Reviewed by Yusuke Suzuki.
+
+ Introduce the new optional parameter "defaultValue" for Table.grow(numOfElementsToAdd, [defaultValue]).
+ It is used to initialize newly added table elements.
+ Introduce the new optional parameter "defaultValue" for Table({initial: N, element:type}, [defaultValue]).
+ After Table is created we append initial times defaultValue to table if it is present.
+ Also add type check for funcref's table for Table.grow, Table ctor and Table.set.
+ Spec: https://webassembly.github.io/reference-types/js-api/index.html#tables.
+
+ * wasm/WasmOperations.cpp:
+ (JSC::Wasm::JSC_DEFINE_JIT_OPERATION):
+ * wasm/WasmTable.cpp:
+ (JSC::Wasm::Table::grow):
+ * wasm/WasmTable.h:
+ (JSC::Wasm::Table::isFuncrefTable const):
+ * wasm/js/JSWebAssemblyTable.cpp:
+ (JSC::JSWebAssemblyTable::grow):
+ * wasm/js/JSWebAssemblyTable.h:
+ * wasm/js/WebAssemblyTableConstructor.cpp:
+ (JSC::JSC_DEFINE_HOST_FUNCTION):
+ * wasm/js/WebAssemblyTablePrototype.cpp:
+ (JSC::JSC_DEFINE_HOST_FUNCTION):
+
2021-01-08 Yusuke Suzuki <[email protected]>
[JSC] AtomicsIsLockFree's AI result is wrong
Modified: trunk/Source/_javascript_Core/wasm/WasmOperations.cpp (271302 => 271303)
--- trunk/Source/_javascript_Core/wasm/WasmOperations.cpp 2021-01-08 18:01:15 UTC (rev 271302)
+++ trunk/Source/_javascript_Core/wasm/WasmOperations.cpp 2021-01-08 18:18:06 UTC (rev 271303)
@@ -749,7 +749,7 @@
{
ASSERT(tableIndex < instance->module().moduleInformation().tableCount());
auto oldSize = instance->table(tableIndex)->length();
- auto newSize = instance->table(tableIndex)->grow(delta);
+ auto newSize = instance->table(tableIndex)->grow(delta, jsNull());
if (!newSize)
return -1;
Modified: trunk/Source/_javascript_Core/wasm/WasmTable.cpp (271302 => 271303)
--- trunk/Source/_javascript_Core/wasm/WasmTable.cpp 2021-01-08 18:01:15 UTC (rev 271302)
+++ trunk/Source/_javascript_Core/wasm/WasmTable.cpp 2021-01-08 18:18:06 UTC (rev 271303)
@@ -79,7 +79,7 @@
RELEASE_ASSERT_NOT_REACHED();
}
-Optional<uint32_t> Table::grow(uint32_t delta)
+Optional<uint32_t> Table::grow(uint32_t delta, JSValue defaultValue)
{
RELEASE_ASSERT(m_owner);
if (delta == 0)
@@ -123,7 +123,7 @@
return WTF::nullopt;
}
- if (!checkedGrow(m_jsValues, [] (WriteBarrier<Unknown>& slot) { slot.setStartingValue(jsNull()); }))
+ if (!checkedGrow(m_jsValues, [defaultValue] (WriteBarrier<Unknown>& slot) { slot.setStartingValue(defaultValue); }))
return WTF::nullopt;
setLength(newLength);
Modified: trunk/Source/_javascript_Core/wasm/WasmTable.h (271302 => 271303)
--- trunk/Source/_javascript_Core/wasm/WasmTable.h 2021-01-08 18:01:15 UTC (rev 271302)
+++ trunk/Source/_javascript_Core/wasm/WasmTable.h 2021-01-08 18:18:06 UTC (rev 271303)
@@ -67,6 +67,7 @@
TableElementType type() const { return m_type; }
bool isExternrefTable() const { return m_type == TableElementType::Externref; }
+ bool isFuncrefTable() const { return m_type == TableElementType::Funcref; }
FuncRefTable* asFuncrefTable();
static bool isValidLength(uint32_t length) { return length < maxTableEntries; }
@@ -75,7 +76,7 @@
void set(uint32_t, JSValue);
JSValue get(uint32_t) const;
- Optional<uint32_t> grow(uint32_t delta);
+ Optional<uint32_t> grow(uint32_t delta, JSValue defaultValue);
void copy(const Table* srcTable, uint32_t dstIndex, uint32_t srcIndex);
void visitAggregate(SlotVisitor&);
Modified: trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyTable.cpp (271302 => 271303)
--- trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyTable.cpp 2021-01-08 18:01:15 UTC (rev 271302)
+++ trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyTable.cpp 2021-01-08 18:18:06 UTC (rev 271303)
@@ -81,11 +81,11 @@
thisObject->table()->visitAggregate(visitor);
}
-bool JSWebAssemblyTable::grow(uint32_t delta)
+bool JSWebAssemblyTable::grow(uint32_t delta, JSValue defaultValue)
{
if (delta == 0)
return true;
- return !!m_table->grow(delta);
+ return !!m_table->grow(delta, defaultValue);
}
JSValue JSWebAssemblyTable::get(uint32_t index)
Modified: trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyTable.h (271302 => 271303)
--- trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyTable.h 2021-01-08 18:01:15 UTC (rev 271302)
+++ trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyTable.h 2021-01-08 18:18:06 UTC (rev 271303)
@@ -58,7 +58,7 @@
Optional<uint32_t> maximum() const { return m_table->maximum(); }
uint32_t length() const { return m_table->length(); }
uint32_t allocatedLength() const { return m_table->allocatedLength(length()); }
- bool grow(uint32_t delta) WARN_UNUSED_RETURN;
+ bool grow(uint32_t delta, JSValue defaultValue) WARN_UNUSED_RETURN;
JSValue get(uint32_t);
void set(uint32_t, WebAssemblyFunction*);
void set(uint32_t, WebAssemblyWrapperFunction*);
Modified: trunk/Source/_javascript_Core/wasm/js/WebAssemblyTableConstructor.cpp (271302 => 271303)
--- trunk/Source/_javascript_Core/wasm/js/WebAssemblyTableConstructor.cpp 2021-01-08 18:01:15 UTC (rev 271302)
+++ trunk/Source/_javascript_Core/wasm/js/WebAssemblyTableConstructor.cpp 2021-01-08 18:18:06 UTC (rev 271303)
@@ -65,7 +65,7 @@
{
JSValue argument = callFrame->argument(0);
if (!argument.isObject())
- return JSValue::encode(throwException(globalObject, throwScope, createTypeError(globalObject, "WebAssembly.Table expects its first argument to be an object"_s)));
+ return throwVMTypeError(globalObject, throwScope, "WebAssembly.Table expects its first argument to be an object"_s);
memoryDescriptor = jsCast<JSObject*>(argument);
}
@@ -81,7 +81,7 @@
else if (elementString == "externref")
type = Wasm::TableElementType::Externref;
else
- return JSValue::encode(throwException(globalObject, throwScope, createTypeError(globalObject, "WebAssembly.Table expects its 'element' field to be the string 'funcref' or 'externref'"_s)));
+ return throwVMTypeError(globalObject, throwScope, "WebAssembly.Table expects its 'element' field to be the string 'funcref' or 'externref'"_s);
}
Identifier initialIdent = Identifier::fromString(vm, "initial");
@@ -109,19 +109,33 @@
maximum = toNonWrappingUint32(globalObject, maxSizeValue);
RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
- if (initial > *maximum) {
- return JSValue::encode(throwException(globalObject, throwScope,
- createRangeError(globalObject, "'maximum' property must be greater than or equal to the 'initial' property"_s)));
- }
+ if (initial > *maximum)
+ return throwVMRangeError(globalObject, throwScope, "'maximum' property must be greater than or equal to the 'initial' property"_s);
}
RefPtr<Wasm::Table> wasmTable = Wasm::Table::tryCreate(initial, maximum, type);
- if (!wasmTable) {
- return JSValue::encode(throwException(globalObject, throwScope,
- createRangeError(globalObject, "couldn't create Table"_s)));
+ if (!wasmTable)
+ return throwVMRangeError(globalObject, throwScope, "couldn't create Table"_s);
+
+ JSWebAssemblyTable* jsWebAssemblyTable = JSWebAssemblyTable::tryCreate(globalObject, vm, webAssemblyTableStructure, wasmTable.releaseNonNull());
+ RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
+
+ JSValue defaultValue = callFrame->argument(1);
+ if (Options::useWebAssemblyReferences() && !defaultValue.isUndefined()) {
+ WebAssemblyFunction* wasmFunction = nullptr;
+ WebAssemblyWrapperFunction* wasmWrapperFunction = nullptr;
+ if (jsWebAssemblyTable->table()->isFuncrefTable() && (!defaultValue.isNull() && !isWebAssemblyHostFunction(vm, defaultValue, wasmFunction, wasmWrapperFunction)))
+ return throwVMTypeError(globalObject, throwScope, "WebAssembly.Table.prototype.constructor expects the second argument to be null or an instance of WebAssembly.Function"_s);
+ for (uint32_t tableIndex = 0; tableIndex < initial; ++tableIndex) {
+ if (jsWebAssemblyTable->table()->isFuncrefTable())
+ jsWebAssemblyTable->set(tableIndex, wasmFunction);
+ if (jsWebAssemblyTable->table()->isExternrefTable())
+ jsWebAssemblyTable->set(tableIndex, defaultValue);
+ RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
+ }
}
- RELEASE_AND_RETURN(throwScope, JSValue::encode(JSWebAssemblyTable::tryCreate(globalObject, vm, webAssemblyTableStructure, wasmTable.releaseNonNull())));
+ RELEASE_AND_RETURN(throwScope, JSValue::encode(jsWebAssemblyTable));
}
JSC_DEFINE_HOST_FUNCTION(callJSWebAssemblyTable, (JSGlobalObject* globalObject, CallFrame*))
Modified: trunk/Source/_javascript_Core/wasm/js/WebAssemblyTablePrototype.cpp (271302 => 271303)
--- trunk/Source/_javascript_Core/wasm/js/WebAssemblyTablePrototype.cpp 2021-01-08 18:01:15 UTC (rev 271302)
+++ trunk/Source/_javascript_Core/wasm/js/WebAssemblyTablePrototype.cpp 2021-01-08 18:18:06 UTC (rev 271303)
@@ -91,10 +91,15 @@
uint32_t delta = toNonWrappingUint32(globalObject, callFrame->argument(0));
RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
+ JSValue defaultValue = jsNull();
+ if (Options::useWebAssemblyReferences() && callFrame->argumentCount() > 1)
+ defaultValue = callFrame->argument(1);
+ if (table->table()->isFuncrefTable() && !defaultValue.isNull() && !isWebAssemblyHostFunction(vm, defaultValue))
+ return throwVMTypeError(globalObject, throwScope, "WebAssembly.Table.prototype.grow expects the second argument to be null or an instance of WebAssembly.Function"_s);
uint32_t oldLength = table->length();
- if (!table->grow(delta))
- return JSValue::encode(throwException(globalObject, throwScope, createRangeError(globalObject, "WebAssembly.Table.prototype.grow could not grow the table"_s)));
+ if (!table->grow(delta, defaultValue))
+ return throwVMRangeError(globalObject, throwScope, "WebAssembly.Table.prototype.grow could not grow the table"_s);
return JSValue::encode(jsNumber(oldLength));
}
@@ -110,7 +115,7 @@
uint32_t index = toNonWrappingUint32(globalObject, callFrame->argument(0));
RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
if (index >= table->length())
- return JSValue::encode(throwException(globalObject, throwScope, createRangeError(globalObject, "WebAssembly.Table.prototype.get expects an integer less than the length of the table"_s)));
+ return throwVMRangeError(globalObject, throwScope, "WebAssembly.Table.prototype.get expects an integer less than the length of the table"_s);
return JSValue::encode(table->get(index));
}
@@ -124,18 +129,20 @@
RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
JSValue value = callFrame->argument(1);
+ if (Options::useWebAssemblyReferences() && value.isUndefined())
+ value = jsNull();
uint32_t index = toNonWrappingUint32(globalObject, callFrame->argument(0));
RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
if (index >= table->length())
- return JSValue::encode(throwException(globalObject, throwScope, createRangeError(globalObject, "WebAssembly.Table.prototype.set expects an integer less than the length of the table"_s)));
+ return throwVMRangeError(globalObject, throwScope, "WebAssembly.Table.prototype.set expects an integer less than the length of the table"_s);
if (table->table()->asFuncrefTable()) {
WebAssemblyFunction* wasmFunction = nullptr;
WebAssemblyWrapperFunction* wasmWrapperFunction = nullptr;
if (!value.isNull() && !isWebAssemblyHostFunction(vm, value, wasmFunction, wasmWrapperFunction))
- return JSValue::encode(throwException(globalObject, throwScope, createTypeError(globalObject, "WebAssembly.Table.prototype.set expects the second argument to be null or an instance of WebAssembly.Function"_s)));
+ return throwVMTypeError(globalObject, throwScope, "WebAssembly.Table.prototype.set expects the second argument to be null or an instance of WebAssembly.Function"_s);
if (value.isNull())
table->clear(index);