[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 7806395cdf389d99890fe1af52d9c983d75722d0..83147aae74e9e1151ca206ca591024766bf24fc0 100644 (file)
@@ -1,3 +1,22 @@
+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
index 72341b463e19fefe214a8375c2463a993182ae2c..274a6d23d8b11508abca1d52529a126a0a85e9a7 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 eb3ea897e166ef633692d7bac05597fd7a344787..25b8e704dd4ad3158996b14696dd81770ce467c2 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 449bc46e7cba1454e771f762c51748424a919019..e5abeaafcf679d00c18db713326e9b800af0ad98 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 591232c68bb0b16bd032417a16cde376cc7f3054..848874c282fc8e22e1e9f426ea9cdd7d5b8ee274 100644 (file)
@@ -1 +1 @@
-export { sum, answer } from "./sum.wasm"
+export { sum, answer, table } from "./sum.wasm"
index 16644dbe48acc59694b7334b16e47ba59b0404c0..44c7c42b889d4132fec2c18767b3d246a17a469a 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 8d936a7cf7264803fc5254fef82619f238f0886f..ca4aaebfcfb3692c9131d3fac97b34511f95242a 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 285f072a8e1269da296978cab69b8be427853a49..7fd965e6da766fdc0b0bdbc8b09f000184e19ede 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 2b4ee92b8cbe13cae0848c1b178776a3a1865f93..54c018acb97c3ddf2c925740ea0524f1449b0383 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 42180c8b6c2ad2308b3a01b67cac095db7668189..63c1d2c8d2f7bfd564ed4e6ebc07febc9e2ae2ff 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 744f0c5aa840f9c364ebf2a4c7ffa231168cd4de..4864c636ce59d9e81e69d9bc5dc2de1249f1f437 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 3e882f63965903bbb2b3ff610d7ab77dd70863db..fcb767b072ce412f6af1478f86c91d48813e56e5 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 de4d4a9507700743f1b221e4cece89809fa5d93c..8a5f9dde7ead36e831dac7b38b9147987abb1bcc 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 aab3b90b3502cd0c829e429709ac5c6e08c76188..8cf0504a8182af521a369279957163c3d93d0a10 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 1f5bd8f179d24caae525c4bad3cc5fab73f69385..be1b42b227b8d53d78cdafca43c09220528c5dc2 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) {