[WebAssembly][Modules] Import tables in wasm modules
authorutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 18 Apr 2018 17:55:15 +0000 (17:55 +0000)
committerutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 18 Apr 2018 17:55:15 +0000 (17:55 +0000)
https://bugs.webkit.org/show_bug.cgi?id=184738

Reviewed by JF Bastien.

JSTests:

* wasm/modules/wasm-imports-js-re-exports-wasm-exports.js:
* wasm/modules/wasm-imports-js-re-exports-wasm-exports/imports.wasm:
* wasm/modules/wasm-imports-js-re-exports-wasm-exports/imports.wat:
* wasm/modules/wasm-imports-js-re-exports-wasm-exports/re-export.js:
* wasm/modules/wasm-imports-js-re-exports-wasm-exports/sum.wasm:
* wasm/modules/wasm-imports-js-re-exports-wasm-exports/sum.wat:
* wasm/modules/wasm-imports-wasm-exports.js:
* wasm/modules/wasm-imports-wasm-exports/imports.wasm:
* wasm/modules/wasm-imports-wasm-exports/imports.wat:
* wasm/modules/wasm-imports-wasm-exports/sum.wasm:
* wasm/modules/wasm-imports-wasm-exports/sum.wat:

Source/JavaScriptCore:

This patch simply allows wasm modules to import table from wasm modules / js re-exporting.
Basically moving JSWebAssemblyInstance's table linking code to WebAssemblyModuleRecord::link
just works.

* wasm/js/JSWebAssemblyInstance.cpp:
(JSC::JSWebAssemblyInstance::create):
* wasm/js/WebAssemblyModuleRecord.cpp:
(JSC::WebAssemblyModuleRecord::link):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@230768 268f45cc-cd09-0410-ab3c-d52691b4dbfc

15 files changed:
JSTests/ChangeLog
JSTests/wasm/modules/wasm-imports-js-re-exports-wasm-exports.js
JSTests/wasm/modules/wasm-imports-js-re-exports-wasm-exports/imports.wasm
JSTests/wasm/modules/wasm-imports-js-re-exports-wasm-exports/imports.wat
JSTests/wasm/modules/wasm-imports-js-re-exports-wasm-exports/re-export.js
JSTests/wasm/modules/wasm-imports-js-re-exports-wasm-exports/sum.wasm
JSTests/wasm/modules/wasm-imports-js-re-exports-wasm-exports/sum.wat
JSTests/wasm/modules/wasm-imports-wasm-exports.js
JSTests/wasm/modules/wasm-imports-wasm-exports/imports.wasm
JSTests/wasm/modules/wasm-imports-wasm-exports/imports.wat
JSTests/wasm/modules/wasm-imports-wasm-exports/sum.wasm
JSTests/wasm/modules/wasm-imports-wasm-exports/sum.wat
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.cpp
Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp

index 7806395..83147aa 100644 (file)
@@ -1,5 +1,24 @@
 2018-04-18  Yusuke Suzuki  <utatane.tea@gmail.com>
 
+        [WebAssembly][Modules] Import tables in wasm modules
+        https://bugs.webkit.org/show_bug.cgi?id=184738
+
+        Reviewed by JF Bastien.
+
+        * wasm/modules/wasm-imports-js-re-exports-wasm-exports.js:
+        * wasm/modules/wasm-imports-js-re-exports-wasm-exports/imports.wasm:
+        * wasm/modules/wasm-imports-js-re-exports-wasm-exports/imports.wat:
+        * wasm/modules/wasm-imports-js-re-exports-wasm-exports/re-export.js:
+        * wasm/modules/wasm-imports-js-re-exports-wasm-exports/sum.wasm:
+        * wasm/modules/wasm-imports-js-re-exports-wasm-exports/sum.wat:
+        * wasm/modules/wasm-imports-wasm-exports.js:
+        * wasm/modules/wasm-imports-wasm-exports/imports.wasm:
+        * wasm/modules/wasm-imports-wasm-exports/imports.wat:
+        * wasm/modules/wasm-imports-wasm-exports/sum.wasm:
+        * wasm/modules/wasm-imports-wasm-exports/sum.wat:
+
+2018-04-18  Yusuke Suzuki  <utatane.tea@gmail.com>
+
         [WebAssembly][Modules] Import globals from wasm modules
         https://bugs.webkit.org/show_bug.cgi?id=184736
 
index 72341b4..274a6d2 100644 (file)
@@ -1,4 +1,4 @@
-import { addOne, getAnswer } from "./wasm-imports-js-re-exports-wasm-exports/imports.wasm"
+import { addOne, getAnswer, table } from "./wasm-imports-js-re-exports-wasm-exports/imports.wasm"
 import * as assert from '../assert.js';
 
 assert.isFunction(addOne);
@@ -7,3 +7,9 @@ assert.eq(addOne(-2), -1);
 assert.eq(addOne(0x7fffffff), -2147483648);
 
 assert.eq(getAnswer(), 42);
+
+assert.eq(table.length, 4);
+assert.eq(table.get(0)(1, 2), 3);
+assert.eq(table.get(1)(-1), 0);
+assert.eq(table.get(2), null);
+assert.eq(table.get(3), null);
index eb3ea89..25b8e70 100644 (file)
Binary files a/JSTests/wasm/modules/wasm-imports-js-re-exports-wasm-exports/imports.wasm and b/JSTests/wasm/modules/wasm-imports-js-re-exports-wasm-exports/imports.wasm differ
index 449bc46..e5abeaa 100644 (file)
@@ -1,6 +1,8 @@
 (module
     (import "./re-export.js" "sum" (func $sum (param i32 i32) (result i32)))
     (import "./re-export.js" "answer" (global i32))
+    (import "./re-export.js" "table" (table $table 4 anyfunc))
+    (export "table" (table $table))
     (type $t0 (func (param i32) (result i32)))
     (func $addOne (export "addOne") (type $t0) (param $p0 i32) (result i32)
         i32.const 1
@@ -8,4 +10,5 @@
         call $sum)
     (type $t1 (func (result i32)))
     (func $getAnswer (export "getAnswer") (type $t1) (result i32)
-        get_global 0))
+        get_global 0)
+    (elem (i32.const 1) $addOne))
index 16644db..44c7c42 100644 (file)
Binary files a/JSTests/wasm/modules/wasm-imports-js-re-exports-wasm-exports/sum.wasm and b/JSTests/wasm/modules/wasm-imports-js-re-exports-wasm-exports/sum.wasm differ
index 8d936a7..ca4aaeb 100644 (file)
@@ -4,4 +4,6 @@
         get_local $p1
         get_local $p0
         i32.add)
-    (global (export "answer") i32 i32.const 42))
+    (global (export "answer") i32 i32.const 42)
+    (table $table (export "table") 4 anyfunc)
+    (elem (i32.const 0) $sum))
index 285f072..7fd965e 100644 (file)
@@ -1,4 +1,5 @@
-import { addOne, getAnswer, getAnswer1, getAnswer2, getAnswer3, getAnswer4 } from "./wasm-imports-wasm-exports/imports.wasm"
+import { addOne, getAnswer, getAnswer1, getAnswer2, getAnswer3, getAnswer4, table } from "./wasm-imports-wasm-exports/imports.wasm"
+import { table as table2 } from "./wasm-imports-wasm-exports/sum.wasm"
 import * as assert from '../assert.js';
 
 assert.isFunction(addOne);
@@ -12,3 +13,10 @@ assert.eq(getAnswer2(), 0.5);
 
 assert.truthy(isPureNaN(getAnswer3()));
 assert.truthy(isPureNaN(getAnswer4()));
+
+assert.eq(table, table2);
+assert.eq(table.length, 4);
+assert.eq(table.get(0)(1, 2), 3);
+assert.eq(table.get(1)(42), 43);
+assert.eq(table.get(2)(), 42);
+assert.eq(table.get(3)(), 0.5);
index 2b4ee92..54c018a 100644 (file)
Binary files a/JSTests/wasm/modules/wasm-imports-wasm-exports/imports.wasm and b/JSTests/wasm/modules/wasm-imports-wasm-exports/imports.wasm differ
index 42180c8..63c1d2c 100644 (file)
@@ -5,6 +5,7 @@
     (import "./sum.wasm" "answer2" (global f64))
     (import "./sum.wasm" "answer3" (global f32))
     (import "./sum.wasm" "answer4" (global f64))
+    (import "./sum.wasm" "table" (table $table 4 anyfunc))
     (type $t0 (func (param i32) (result i32)))
     (func $addOne (export "addOne") (type $t0) (param $p0 i32) (result i32)
         i32.const 1
@@ -23,4 +24,5 @@
         get_global 3)
     (func $getAnswer4 (export "getAnswer4") (type $t3) (result f64)
         get_global 4)
-    )
+    (export "table" (table $table))
+    (elem (i32.const 1) $addOne $getAnswer $getAnswer1))
index 744f0c5..4864c63 100644 (file)
Binary files a/JSTests/wasm/modules/wasm-imports-wasm-exports/sum.wasm and b/JSTests/wasm/modules/wasm-imports-wasm-exports/sum.wasm differ
index 3e882f6..fcb767b 100644 (file)
@@ -1,4 +1,5 @@
 (module
+    (table $table (export "table") 4 anyfunc)
     (type $t0 (func (param i32 i32) (result i32)))
     (func $sum (export "sum") (type $t0) (param $p0 i32) (param $p1 i32) (result i32)
         get_local $p1
@@ -8,4 +9,5 @@
     (global (export "answer1") f32 f32.const 0.5)
     (global (export "answer2") f64 f64.const 0.5)
     (global (export "answer3") f32 f32.const nan)
-    (global (export "answer4") f64 f64.const nan))
+    (global (export "answer4") f64 f64.const nan)
+    (elem (i32.const 0) $sum))
index de4d4a9..8a5f9dd 100644 (file)
@@ -1,3 +1,19 @@
+2018-04-18  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        [WebAssembly][Modules] Import tables in wasm modules
+        https://bugs.webkit.org/show_bug.cgi?id=184738
+
+        Reviewed by JF Bastien.
+
+        This patch simply allows wasm modules to import table from wasm modules / js re-exporting.
+        Basically moving JSWebAssemblyInstance's table linking code to WebAssemblyModuleRecord::link
+        just works.
+
+        * wasm/js/JSWebAssemblyInstance.cpp:
+        (JSC::JSWebAssemblyInstance::create):
+        * wasm/js/WebAssemblyModuleRecord.cpp:
+        (JSC::WebAssemblyModuleRecord::link):
+
 2018-04-18  Dominik Infuehr  <dinfuehr@igalia.com>
 
         [ARM] Fix build error and crash after PtrTag change
index aab3b90..8cf0504 100644 (file)
@@ -181,7 +181,6 @@ JSWebAssemblyInstance* JSWebAssemblyInstance::create(VM& vm, ExecState* exec, co
     // Let funcs, memories and tables be initially-empty lists of callable JavaScript objects, WebAssembly.Memory objects and WebAssembly.Table objects, respectively.
     // Let imports be an initially-empty list of external values.
     bool hasMemoryImport = false;
-    bool hasTableImport = false;
 
     if (creationMode == Wasm::CreationMode::FromJS) {
         // If the list of module.imports is not empty and Type(importObject) is not Object, a TypeError is thrown.
@@ -206,8 +205,8 @@ JSWebAssemblyInstance* JSWebAssemblyInstance::create(VM& vm, ExecState* exec, co
         switch (import.kind) {
         case Wasm::ExternalKind::Function:
         case Wasm::ExternalKind::Global:
-            continue;
         case Wasm::ExternalKind::Table:
+            continue;
         case Wasm::ExternalKind::Memory:
             break;
         }
@@ -232,37 +231,9 @@ JSWebAssemblyInstance* JSWebAssemblyInstance::create(VM& vm, ExecState* exec, co
         switch (import.kind) {
         case Wasm::ExternalKind::Function:
         case Wasm::ExternalKind::Global:
+        case Wasm::ExternalKind::Table:
             break;
 
-        case Wasm::ExternalKind::Table: {
-            RELEASE_ASSERT(!hasTableImport); // This should be guaranteed by a validation failure.
-            // 7. Otherwise (i is a table import):
-            hasTableImport = true;
-            JSWebAssemblyTable* table = jsDynamicCast<JSWebAssemblyTable*>(vm, value);
-            // i. If v is not a WebAssembly.Table object, throw a WebAssembly.LinkError.
-            if (!table)
-                return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "Table import", "is not an instance of WebAssembly.Table")));
-
-            uint32_t expectedInitial = moduleInformation.tableInformation.initial();
-            uint32_t actualInitial = table->length();
-            if (actualInitial < expectedInitial)
-                return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "Table import", "provided an 'initial' that is too small")));
-
-            if (std::optional<uint32_t> expectedMaximum = moduleInformation.tableInformation.maximum()) {
-                std::optional<uint32_t> actualMaximum = table->maximum();
-                if (!actualMaximum)
-                    return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "Table import", "does not have a 'maximum' but the module requires that it does")));
-                if (*actualMaximum > *expectedMaximum)
-                    return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "Imported Table", "'maximum' is larger than the module's expected 'maximum'")));
-            }
-
-            // ii. Append v to tables.
-            // iii. Append v.[[Table]] to imports.
-            jsInstance->setTable(vm, table);
-            RETURN_IF_EXCEPTION(throwScope, nullptr);
-            break;
-        }
-
         case Wasm::ExternalKind::Memory: {
             // 6. If i is a memory import:
             RELEASE_ASSERT(!hasMemoryImport); // This should be guaranteed by a validation failure.
@@ -322,28 +293,6 @@ JSWebAssemblyInstance* JSWebAssemblyInstance::create(VM& vm, ExecState* exec, co
             RETURN_IF_EXCEPTION(throwScope, nullptr);
         }
     }
-
-    {
-        if (!!moduleInformation.tableInformation && moduleInformation.tableInformation.isImport()) {
-            // We should either have a Table import or we should have thrown an exception.
-            RELEASE_ASSERT(hasTableImport);
-        }
-
-        if (!!moduleInformation.tableInformation && !hasTableImport) {
-            RELEASE_ASSERT(!moduleInformation.tableInformation.isImport());
-            // We create a Table when it's a Table definition.
-            RefPtr<Wasm::Table> wasmTable = Wasm::Table::create(moduleInformation.tableInformation.initial(), moduleInformation.tableInformation.maximum());
-            if (!wasmTable)
-                return exception(createJSWebAssemblyLinkError(exec, vm, "couldn't create Table"));
-            JSWebAssemblyTable* table = JSWebAssemblyTable::create(exec, vm, globalObject->WebAssemblyTableStructure(), wasmTable.releaseNonNull());
-            // We should always be able to allocate a JSWebAssemblyTable we've defined.
-            // If it's defined to be too large, we should have thrown a validation error.
-            throwScope.assertNoException();
-            ASSERT(table);
-            jsInstance->setTable(vm, table);
-            RETURN_IF_EXCEPTION(throwScope, nullptr);
-        }
-    }
     
     if (!jsInstance->memory()) {
         // Make sure we have a dummy memory, so that wasm -> wasm thunks avoid checking for a nullptr Memory when trying to set pinned registers.
index 1f5bd8f..be1b42b 100644 (file)
@@ -113,14 +113,16 @@ void WebAssemblyModuleRecord::link(ExecState* exec, JSValue, JSObject* importObj
         return makeString(before, " ", String::fromUTF8(import.module), ":", String::fromUTF8(import.field), " ", after);
     };
 
+    bool hasTableImport = false;
+
     for (const auto& import : moduleInformation.imports) {
         // Validation and linking other than Wasm::ExternalKind::Function is already done in JSWebAssemblyInstance.
         // Eventually we will move all the linking code in JSWebAssemblyInstance here and remove this switch statement.
         switch (import.kind) {
         case Wasm::ExternalKind::Function:
         case Wasm::ExternalKind::Global:
-            break;
         case Wasm::ExternalKind::Table:
+            break;
         case Wasm::ExternalKind::Memory:
             continue;
         }
@@ -253,12 +255,62 @@ void WebAssemblyModuleRecord::link(ExecState* exec, JSValue, JSObject* importObj
             break;
         }
 
-        case Wasm::ExternalKind::Table:
+        case Wasm::ExternalKind::Table: {
+            RELEASE_ASSERT(!hasTableImport); // This should be guaranteed by a validation failure.
+            // 7. Otherwise (i is a table import):
+            hasTableImport = true;
+            JSWebAssemblyTable* table = jsDynamicCast<JSWebAssemblyTable*>(vm, value);
+            // i. If v is not a WebAssembly.Table object, throw a WebAssembly.LinkError.
+            if (!table)
+                return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "Table import", "is not an instance of WebAssembly.Table")));
+
+            uint32_t expectedInitial = moduleInformation.tableInformation.initial();
+            uint32_t actualInitial = table->length();
+            if (actualInitial < expectedInitial)
+                return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "Table import", "provided an 'initial' that is too small")));
+
+            if (std::optional<uint32_t> expectedMaximum = moduleInformation.tableInformation.maximum()) {
+                std::optional<uint32_t> actualMaximum = table->maximum();
+                if (!actualMaximum)
+                    return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "Table import", "does not have a 'maximum' but the module requires that it does")));
+                if (*actualMaximum > *expectedMaximum)
+                    return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "Imported Table", "'maximum' is larger than the module's expected 'maximum'")));
+            }
+
+            // ii. Append v to tables.
+            // iii. Append v.[[Table]] to imports.
+            m_instance->setTable(vm, table);
+            RETURN_IF_EXCEPTION(scope, void());
+            break;
+        }
+
         case Wasm::ExternalKind::Memory:
             break;
         }
     }
 
+    {
+        if (!!moduleInformation.tableInformation && moduleInformation.tableInformation.isImport()) {
+            // We should either have a Table import or we should have thrown an exception.
+            RELEASE_ASSERT(hasTableImport);
+        }
+
+        if (!!moduleInformation.tableInformation && !hasTableImport) {
+            RELEASE_ASSERT(!moduleInformation.tableInformation.isImport());
+            // We create a Table when it's a Table definition.
+            RefPtr<Wasm::Table> wasmTable = Wasm::Table::create(moduleInformation.tableInformation.initial(), moduleInformation.tableInformation.maximum());
+            if (!wasmTable)
+                return exception(createJSWebAssemblyLinkError(exec, vm, "couldn't create Table"));
+            JSWebAssemblyTable* table = JSWebAssemblyTable::create(exec, vm, globalObject->WebAssemblyTableStructure(), wasmTable.releaseNonNull());
+            // We should always be able to allocate a JSWebAssemblyTable we've defined.
+            // If it's defined to be too large, we should have thrown a validation error.
+            scope.assertNoException();
+            ASSERT(table);
+            m_instance->setTable(vm, table);
+            RETURN_IF_EXCEPTION(scope, void());
+        }
+    }
+
     // Globals
     {
         for (size_t globalIndex = moduleInformation.firstInternalGlobal; globalIndex < moduleInformation.globals.size(); ++globalIndex) {