Title: [271303] trunk
Revision
271303
Author
[email protected]
Date
2021-01-08 10:18:06 -0800 (Fri, 08 Jan 2021)

Log Message

[WASM-References] Add optional default value parameter for Table.constructor, Table.grow and Table.set
https://bugs.webkit.org/show_bug.cgi?id=220323

Patch by Dmitry Bezhetskov <[email protected]> on 2021-01-08
Reviewed by Yusuke Suzuki.

JSTests:

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):

Source/_javascript_Core:

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):

Modified Paths

Added Paths

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);
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to