Title: [286703] trunk
Revision
286703
Author
[email protected]
Date
2021-12-08 12:27:51 -0800 (Wed, 08 Dec 2021)

Log Message

Support WebAssembly.Memory imports in Wasm/ESM modules.
https://bugs.webkit.org/show_bug.cgi?id=184745

Patch by Asumu Takikawa <[email protected]> on 2021-12-08
Reviewed by Yusuke Suzuki.

JSTests:

* wasm/modules/wasm-imports-js-exports.js:
(then):
* wasm/modules/wasm-imports-js-exports/memory-fail-1.js: Added.
* wasm/modules/wasm-imports-js-exports/memory-fail-1.wasm: Added.
* wasm/modules/wasm-imports-js-exports/memory-fail-1.wat: Added.
* wasm/modules/wasm-imports-js-exports/memory-fail-2.js: Added.
* wasm/modules/wasm-imports-js-exports/memory-fail-2.wasm: Added.
* wasm/modules/wasm-imports-js-exports/memory-fail-2.wat: Added.
* wasm/modules/wasm-imports-js-exports/memory-fail-3.js: Added.
* wasm/modules/wasm-imports-js-exports/memory-fail-3.wasm: Added.
* wasm/modules/wasm-imports-js-exports/memory-fail-3.wat: Added.
* wasm/modules/wasm-imports-js-exports/memory-fail-4.js: Added.
* wasm/modules/wasm-imports-js-exports/memory-fail-4.wasm: Added.
* wasm/modules/wasm-imports-js-exports/memory-fail-4.wat: Added.
* wasm/modules/wasm-imports-js-exports/memory-fail-5.js: Added.
* wasm/modules/wasm-imports-js-exports/memory-fail-5.wasm: Added.
* wasm/modules/wasm-imports-js-exports/memory-fail-5.wat: Added.
* wasm/modules/wasm-imports-js-exports/memory.js: Added.
(export.setMemory):
* wasm/modules/wasm-imports-js-exports/memory.wasm: Added.
* wasm/modules/wasm-imports-js-exports/memory.wat: Added.
* wasm/modules/wasm-imports-js-exports/shared-memory.js: Added.
* wasm/modules/wasm-imports-js-exports/shared-memory.wasm: Added.
* wasm/modules/wasm-imports-js-exports/shared-memory.wat: Added.
* 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:

Source/_javascript_Core:

Changes how Wasm code is initialized for modules that are loaded
by the module loader and have memory imports. The initial code for
the LLInt tier is copied to all memory modes, so that the memory
import can be initialized after compilation. When LLInt is turned
off, the compilation of B3/Air code is delayed until the memory is
initialized.

* wasm/WasmCodeBlock.cpp:
(JSC::Wasm::CodeBlock::createFromExisting):
(JSC::Wasm::CodeBlock::CodeBlock):
* wasm/WasmCodeBlock.h:
* wasm/WasmInstance.h:
(JSC::Wasm::Instance::finalizeCreation):
(JSC::Wasm::Instance::module const):
(JSC::Wasm::Instance::codeBlock const):
(JSC::Wasm::Instance::memory const):
(JSC::Wasm::Instance::isImportFunction const):
(JSC::Wasm::Instance::module): Deleted.
(JSC::Wasm::Instance::codeBlock): Deleted.
(JSC::Wasm::Instance::memory): Deleted.
* wasm/WasmModule.cpp:
(JSC::Wasm::Module::copyInitialCodeBlockToAllMemoryModes):
* wasm/WasmModule.h:
* wasm/js/JSWebAssembly.cpp:
(JSC::instantiate):
* wasm/js/JSWebAssemblyInstance.cpp:
(JSC::JSWebAssemblyInstance::finalizeCreation):
(JSC::JSWebAssemblyInstance::tryCreate):
* wasm/js/JSWebAssemblyInstance.h:
* wasm/js/WebAssemblyModuleRecord.cpp:
(JSC::WebAssemblyModuleRecord::initializeImportsAndExports):

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (286702 => 286703)


--- trunk/JSTests/ChangeLog	2021-12-08 20:27:32 UTC (rev 286702)
+++ trunk/JSTests/ChangeLog	2021-12-08 20:27:51 UTC (rev 286703)
@@ -1,3 +1,41 @@
+2021-12-08  Asumu Takikawa  <[email protected]>
+
+        Support WebAssembly.Memory imports in Wasm/ESM modules.
+        https://bugs.webkit.org/show_bug.cgi?id=184745
+
+        Reviewed by Yusuke Suzuki.
+
+        * wasm/modules/wasm-imports-js-exports.js:
+        (then):
+        * wasm/modules/wasm-imports-js-exports/memory-fail-1.js: Added.
+        * wasm/modules/wasm-imports-js-exports/memory-fail-1.wasm: Added.
+        * wasm/modules/wasm-imports-js-exports/memory-fail-1.wat: Added.
+        * wasm/modules/wasm-imports-js-exports/memory-fail-2.js: Added.
+        * wasm/modules/wasm-imports-js-exports/memory-fail-2.wasm: Added.
+        * wasm/modules/wasm-imports-js-exports/memory-fail-2.wat: Added.
+        * wasm/modules/wasm-imports-js-exports/memory-fail-3.js: Added.
+        * wasm/modules/wasm-imports-js-exports/memory-fail-3.wasm: Added.
+        * wasm/modules/wasm-imports-js-exports/memory-fail-3.wat: Added.
+        * wasm/modules/wasm-imports-js-exports/memory-fail-4.js: Added.
+        * wasm/modules/wasm-imports-js-exports/memory-fail-4.wasm: Added.
+        * wasm/modules/wasm-imports-js-exports/memory-fail-4.wat: Added.
+        * wasm/modules/wasm-imports-js-exports/memory-fail-5.js: Added.
+        * wasm/modules/wasm-imports-js-exports/memory-fail-5.wasm: Added.
+        * wasm/modules/wasm-imports-js-exports/memory-fail-5.wat: Added.
+        * wasm/modules/wasm-imports-js-exports/memory.js: Added.
+        (export.setMemory):
+        * wasm/modules/wasm-imports-js-exports/memory.wasm: Added.
+        * wasm/modules/wasm-imports-js-exports/memory.wat: Added.
+        * wasm/modules/wasm-imports-js-exports/shared-memory.js: Added.
+        * wasm/modules/wasm-imports-js-exports/shared-memory.wasm: Added.
+        * wasm/modules/wasm-imports-js-exports/shared-memory.wat: Added.
+        * 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:
+
 2021-12-07  Saam Barati  <[email protected]>
 
         TypedArray prototype set should go down the fast path when using non clamped integer types of the same byte size

Added: trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory-fail-1.js (0 => 286703)


--- trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory-fail-1.js	                        (rev 0)
+++ trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory-fail-1.js	2021-12-08 20:27:51 UTC (rev 286703)
@@ -0,0 +1 @@
+export let memory = 3;

Added: trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory-fail-1.wasm (0 => 286703)


--- trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory-fail-1.wasm	                        (rev 0)
+++ trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory-fail-1.wasm	2021-12-08 20:27:51 UTC (rev 286703)
@@ -0,0 +1 @@
+��asm������./memory-fail-1.jsmemory��
\ No newline at end of file

Added: trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory-fail-1.wat (0 => 286703)


--- trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory-fail-1.wat	                        (rev 0)
+++ trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory-fail-1.wat	2021-12-08 20:27:51 UTC (rev 286703)
@@ -0,0 +1,2 @@
+(module
+    (import "./memory-fail-1.js" "memory" (memory $m 1)))

Added: trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory-fail-2.js (0 => 286703)


--- trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory-fail-2.js	                        (rev 0)
+++ trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory-fail-2.js	2021-12-08 20:27:51 UTC (rev 286703)
@@ -0,0 +1,3 @@
+export let memory = new WebAssembly.Memory({
+    initial: 1,
+});

Added: trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory-fail-2.wasm (0 => 286703)


--- trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory-fail-2.wasm	                        (rev 0)
+++ trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory-fail-2.wasm	2021-12-08 20:27:51 UTC (rev 286703)
@@ -0,0 +1 @@
+��asm������./memory-fail-2.jsmemory��
\ No newline at end of file

Added: trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory-fail-2.wat (0 => 286703)


--- trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory-fail-2.wat	                        (rev 0)
+++ trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory-fail-2.wat	2021-12-08 20:27:51 UTC (rev 286703)
@@ -0,0 +1,2 @@
+(module
+    (import "./memory-fail-2.js" "memory" (memory $m 4)))

Added: trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory-fail-3.js (0 => 286703)


--- trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory-fail-3.js	                        (rev 0)
+++ trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory-fail-3.js	2021-12-08 20:27:51 UTC (rev 286703)
@@ -0,0 +1,3 @@
+export let memory = new WebAssembly.Memory({
+    initial: 1,
+});

Added: trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory-fail-3.wasm (0 => 286703)


--- trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory-fail-3.wasm	                        (rev 0)
+++ trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory-fail-3.wasm	2021-12-08 20:27:51 UTC (rev 286703)
@@ -0,0 +1 @@
+��asm������./memory-fail-3.jsmemory

Added: trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory-fail-3.wat (0 => 286703)


--- trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory-fail-3.wat	                        (rev 0)
+++ trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory-fail-3.wat	2021-12-08 20:27:51 UTC (rev 286703)
@@ -0,0 +1,2 @@
+(module
+    (import "./memory-fail-3.js" "memory" (memory $m 1 10)))

Added: trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory-fail-4.js (0 => 286703)


--- trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory-fail-4.js	                        (rev 0)
+++ trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory-fail-4.js	2021-12-08 20:27:51 UTC (rev 286703)
@@ -0,0 +1,4 @@
+export let memory = new WebAssembly.Memory({
+    initial: 1,
+    maximum: 11
+});

Added: trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory-fail-4.wasm (0 => 286703)


--- trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory-fail-4.wasm	                        (rev 0)
+++ trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory-fail-4.wasm	2021-12-08 20:27:51 UTC (rev 286703)
@@ -0,0 +1 @@
+��asm������./memory-fail-4.jsmemory

Added: trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory-fail-4.wat (0 => 286703)


--- trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory-fail-4.wat	                        (rev 0)
+++ trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory-fail-4.wat	2021-12-08 20:27:51 UTC (rev 286703)
@@ -0,0 +1,2 @@
+(module
+    (import "./memory-fail-4.js" "memory" (memory $m 1 10)))

Added: trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory-fail-5.js (0 => 286703)


--- trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory-fail-5.js	                        (rev 0)
+++ trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory-fail-5.js	2021-12-08 20:27:51 UTC (rev 286703)
@@ -0,0 +1,5 @@
+export let memory = new WebAssembly.Memory({
+    initial: 1,
+    maximum: 10,
+    shared: false,
+});

Added: trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory-fail-5.wasm (0 => 286703)


--- trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory-fail-5.wasm	                        (rev 0)
+++ trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory-fail-5.wasm	2021-12-08 20:27:51 UTC (rev 286703)
@@ -0,0 +1 @@
+��asm������./memory-fail-5.jsmemory

Added: trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory-fail-5.wat (0 => 286703)


--- trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory-fail-5.wat	                        (rev 0)
+++ trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory-fail-5.wat	2021-12-08 20:27:51 UTC (rev 286703)
@@ -0,0 +1,2 @@
+(module
+    (import "./memory-fail-5.js" "memory" (memory $m 1 10 shared)))

Added: trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory.js (0 => 286703)


--- trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory.js	                        (rev 0)
+++ trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory.js	2021-12-08 20:27:51 UTC (rev 286703)
@@ -0,0 +1,10 @@
+export let memory = new WebAssembly.Memory({
+    initial: 1,
+});
+
+export function setMemory(mem) {
+    memory = mem;
+}
+
+const b = new Int8Array(memory.buffer);
+b[0] = 42;

Added: trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory.wasm (0 => 286703)


--- trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory.wasm	                        (rev 0)
+++ trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory.wasm	2021-12-08 20:27:51 UTC (rev 286703)
@@ -0,0 +1,3 @@
+��asm������`./memory.jsmemory����
+getMem����
+	�� ��-����
\ No newline at end of file

Added: trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory.wat (0 => 286703)


--- trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory.wat	                        (rev 0)
+++ trunk/JSTests/wasm/modules/wasm-imports-js-exports/memory.wat	2021-12-08 20:27:51 UTC (rev 286703)
@@ -0,0 +1,4 @@
+(module
+    (import "./memory.js" "memory" (memory $m 1))
+    (func (export "getMem") (param i32) (result i32)
+        (i32.load8_u (local.get 0))))

Added: trunk/JSTests/wasm/modules/wasm-imports-js-exports/shared-memory.js (0 => 286703)


--- trunk/JSTests/wasm/modules/wasm-imports-js-exports/shared-memory.js	                        (rev 0)
+++ trunk/JSTests/wasm/modules/wasm-imports-js-exports/shared-memory.js	2021-12-08 20:27:51 UTC (rev 286703)
@@ -0,0 +1,8 @@
+export const memory = new WebAssembly.Memory({
+    initial: 1,
+    maximum: 10,
+    shared: true
+});
+
+const b = new Int8Array(memory.buffer);
+b[0] = 42;

Added: trunk/JSTests/wasm/modules/wasm-imports-js-exports/shared-memory.wasm (0 => 286703)


--- trunk/JSTests/wasm/modules/wasm-imports-js-exports/shared-memory.wasm	                        (rev 0)
+++ trunk/JSTests/wasm/modules/wasm-imports-js-exports/shared-memory.wasm	2021-12-08 20:27:51 UTC (rev 286703)
@@ -0,0 +1,4 @@
+��asm������`./shared-memory.jsmemory
+��
+getMem����
+	�� ��-����
\ No newline at end of file

Added: trunk/JSTests/wasm/modules/wasm-imports-js-exports/shared-memory.wat (0 => 286703)


--- trunk/JSTests/wasm/modules/wasm-imports-js-exports/shared-memory.wat	                        (rev 0)
+++ trunk/JSTests/wasm/modules/wasm-imports-js-exports/shared-memory.wat	2021-12-08 20:27:51 UTC (rev 286703)
@@ -0,0 +1,4 @@
+(module
+    (import "./shared-memory.js" "memory" (memory $m 1 10 shared))
+    (func (export "getMem") (param i32) (result i32)
+        (i32.load8_u (local.get 0))))

Modified: trunk/JSTests/wasm/modules/wasm-imports-js-exports.js (286702 => 286703)


--- trunk/JSTests/wasm/modules/wasm-imports-js-exports.js	2021-12-08 20:27:32 UTC (rev 286702)
+++ trunk/JSTests/wasm/modules/wasm-imports-js-exports.js	2021-12-08 20:27:51 UTC (rev 286703)
@@ -18,3 +18,37 @@
 
 assert.isFunction(getElem);
 assert.eq(getElem(), "foo");
+
+import { getMem } from "./wasm-imports-js-exports/memory.wasm";
+
+assert.isFunction(getMem);
+assert.eq(getMem(0), 42);
+assert.eq(getMem(65535), 0);
+assert.throws(() => getMem(65536), WebAssembly.RuntimeError, "Out of bounds memory access");
+
+import { getMem as sharedGetMem } from "./wasm-imports-js-exports/shared-memory.wasm";
+
+assert.isFunction(sharedGetMem);
+assert.eq(sharedGetMem(0), 42);
+assert.eq(sharedGetMem(65535), 0);
+assert.throws(() => sharedGetMem(65536), WebAssembly.RuntimeError, "Out of bounds memory access");
+
+import("./wasm-imports-js-exports/memory-fail-1.wasm").then($vm.abort, function (error) {
+    assert.eq(String(error), `LinkError: Memory import ./memory-fail-1.js:memory is not an instance of WebAssembly.Memory`);
+}).then(function () { }, $vm.abort);
+
+import("./wasm-imports-js-exports/memory-fail-2.wasm").then($vm.abort, function (error) {
+    assert.eq(String(error), `LinkError: Memory import ./memory-fail-2.js:memory provided an 'initial' that is smaller than the module's declared 'initial' import memory size`);
+}).then(function () { }, $vm.abort);
+
+import("./wasm-imports-js-exports/memory-fail-3.wasm").then($vm.abort, function (error) {
+    assert.eq(String(error), `LinkError: Memory import ./memory-fail-3.js:memory did not have a 'maximum' but the module requires that it does`);
+}).then(function () { }, $vm.abort);
+
+import("./wasm-imports-js-exports/memory-fail-4.wasm").then($vm.abort, function (error) {
+    assert.eq(String(error), `LinkError: Memory import ./memory-fail-4.js:memory provided a 'maximum' that is larger than the module's declared 'maximum' import memory size`);
+}).then(function () { }, $vm.abort);
+
+import("./wasm-imports-js-exports/memory-fail-5.wasm").then($vm.abort, function (error) {
+    assert.eq(String(error), `LinkError: Memory import ./memory-fail-5.js:memory provided a 'shared' that is different from the module's declared 'shared' import memory attribute`);
+}).then(function () { }, $vm.abort);

Modified: trunk/JSTests/wasm/modules/wasm-imports-js-re-exports-wasm-exports/imports.wasm (286702 => 286703)


--- trunk/JSTests/wasm/modules/wasm-imports-js-re-exports-wasm-exports/imports.wasm	2021-12-08 20:27:32 UTC (rev 286702)
+++ trunk/JSTests/wasm/modules/wasm-imports-js-re-exports-wasm-exports/imports.wasm	2021-12-08 20:27:51 UTC (rev 286703)
@@ -1,2 +1,2 @@
-��asm������``��`H./re-export.jssum��./re-export.jsanswer��./re-export.jstablep����table��addOne��	getAnswer��	��A
+��asm������``��`b./re-export.jssum��./re-export.jsanswer��./re-export.jstablep��./re-export.jsmemory��'table��memory��addOne��	getAnswer��	��A
 ��A ������#��
\ No newline at end of file

Modified: trunk/JSTests/wasm/modules/wasm-imports-js-re-exports-wasm-exports/imports.wat (286702 => 286703)


--- trunk/JSTests/wasm/modules/wasm-imports-js-re-exports-wasm-exports/imports.wat	2021-12-08 20:27:32 UTC (rev 286702)
+++ trunk/JSTests/wasm/modules/wasm-imports-js-re-exports-wasm-exports/imports.wat	2021-12-08 20:27:51 UTC (rev 286703)
@@ -2,7 +2,9 @@
     (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 funcref))
+    (import "./re-export.js" "memory" (memory $memory 1 1))
     (export "table" (table $table))
+    (export "memory" (memory $memory))
     (type $t0 (func (param i32) (result i32)))
     (func $addOne (export "addOne") (type $t0) (param $p0 i32) (result i32)
         i32.const 1

Modified: trunk/JSTests/wasm/modules/wasm-imports-js-re-exports-wasm-exports/re-export.js (286702 => 286703)


--- trunk/JSTests/wasm/modules/wasm-imports-js-re-exports-wasm-exports/re-export.js	2021-12-08 20:27:32 UTC (rev 286702)
+++ trunk/JSTests/wasm/modules/wasm-imports-js-re-exports-wasm-exports/re-export.js	2021-12-08 20:27:51 UTC (rev 286703)
@@ -1 +1 @@
-export { sum, answer, table } from "./sum.wasm"
+export { sum, answer, table, memory } from "./sum.wasm"

Modified: trunk/JSTests/wasm/modules/wasm-imports-js-re-exports-wasm-exports/sum.wasm (286702 => 286703)


--- trunk/JSTests/wasm/modules/wasm-imports-js-re-exports-wasm-exports/sum.wasm	2021-12-08 20:27:32 UTC (rev 286702)
+++ trunk/JSTests/wasm/modules/wasm-imports-js-re-exports-wasm-exports/sum.wasm	2021-12-08 20:27:51 UTC (rev 286703)
@@ -1,2 +1,3 @@
-��asm������`��p����A*sum����answer��table��	��A����
-	��  ��j
\ No newline at end of file
+��asm������`��p����A*!sum����answer��table��memory��	��A����
+	��  ��j
+��A����
\ No newline at end of file

Modified: trunk/JSTests/wasm/modules/wasm-imports-js-re-exports-wasm-exports/sum.wat (286702 => 286703)


--- trunk/JSTests/wasm/modules/wasm-imports-js-re-exports-wasm-exports/sum.wat	2021-12-08 20:27:32 UTC (rev 286702)
+++ trunk/JSTests/wasm/modules/wasm-imports-js-re-exports-wasm-exports/sum.wat	2021-12-08 20:27:51 UTC (rev 286703)
@@ -6,4 +6,6 @@
         i32.add)
     (global (export "answer") i32 i32.const 42)
     (table $table (export "table") 4 funcref)
+    (memory $memory (export "memory") 1 1)
+    (data (i32.const 4) "\10\00\10\00")
     (elem (i32.const 0) $sum))

Modified: trunk/JSTests/wasm/modules/wasm-imports-js-re-exports-wasm-exports.js (286702 => 286703)


--- trunk/JSTests/wasm/modules/wasm-imports-js-re-exports-wasm-exports.js	2021-12-08 20:27:32 UTC (rev 286702)
+++ trunk/JSTests/wasm/modules/wasm-imports-js-re-exports-wasm-exports.js	2021-12-08 20:27:51 UTC (rev 286703)
@@ -1,4 +1,4 @@
-import { addOne, getAnswer, table } from "./wasm-imports-js-re-exports-wasm-exports/imports.wasm"
+import { addOne, getAnswer, table, memory } from "./wasm-imports-js-re-exports-wasm-exports/imports.wasm"
 import * as assert from '../assert.js';
 
 assert.isFunction(addOne);
@@ -13,3 +13,13 @@
 assert.eq(table.get(1)(-1), 0);
 assert.eq(table.get(2), null);
 assert.eq(table.get(3), null);
+
+assert.eq(memory.buffer.byteLength, 65536);
+const buf = new Uint8Array(memory.buffer);
+assert.eq(buf[4], 0x10);
+assert.eq(buf[5], 0x00);
+assert.eq(buf[6], 0x10);
+assert.eq(buf[7], 0x00);
+buf[0] = 0x42;
+assert.eq(buf[0], 0x42);
+assert.eq(buf[65536], undefined);

Modified: trunk/Source/_javascript_Core/ChangeLog (286702 => 286703)


--- trunk/Source/_javascript_Core/ChangeLog	2021-12-08 20:27:32 UTC (rev 286702)
+++ trunk/Source/_javascript_Core/ChangeLog	2021-12-08 20:27:51 UTC (rev 286703)
@@ -1,3 +1,42 @@
+2021-12-08  Asumu Takikawa  <[email protected]>
+
+        Support WebAssembly.Memory imports in Wasm/ESM modules.
+        https://bugs.webkit.org/show_bug.cgi?id=184745
+
+        Reviewed by Yusuke Suzuki.
+
+        Changes how Wasm code is initialized for modules that are loaded
+        by the module loader and have memory imports. The initial code for
+        the LLInt tier is copied to all memory modes, so that the memory
+        import can be initialized after compilation. When LLInt is turned
+        off, the compilation of B3/Air code is delayed until the memory is
+        initialized.
+
+        * wasm/WasmCodeBlock.cpp:
+        (JSC::Wasm::CodeBlock::createFromExisting):
+        (JSC::Wasm::CodeBlock::CodeBlock):
+        * wasm/WasmCodeBlock.h:
+        * wasm/WasmInstance.h:
+        (JSC::Wasm::Instance::finalizeCreation):
+        (JSC::Wasm::Instance::module const):
+        (JSC::Wasm::Instance::codeBlock const):
+        (JSC::Wasm::Instance::memory const):
+        (JSC::Wasm::Instance::isImportFunction const):
+        (JSC::Wasm::Instance::module): Deleted.
+        (JSC::Wasm::Instance::codeBlock): Deleted.
+        (JSC::Wasm::Instance::memory): Deleted.
+        * wasm/WasmModule.cpp:
+        (JSC::Wasm::Module::copyInitialCodeBlockToAllMemoryModes):
+        * wasm/WasmModule.h:
+        * wasm/js/JSWebAssembly.cpp:
+        (JSC::instantiate):
+        * wasm/js/JSWebAssemblyInstance.cpp:
+        (JSC::JSWebAssemblyInstance::finalizeCreation):
+        (JSC::JSWebAssemblyInstance::tryCreate):
+        * wasm/js/JSWebAssemblyInstance.h:
+        * wasm/js/WebAssemblyModuleRecord.cpp:
+        (JSC::WebAssemblyModuleRecord::initializeImportsAndExports):
+
 2021-12-08  Yusuke Suzuki  <[email protected]>
 
         [JSC] Introduce WriteBarrierStructureID

Modified: trunk/Source/_javascript_Core/wasm/WasmCodeBlock.cpp (286702 => 286703)


--- trunk/Source/_javascript_Core/wasm/WasmCodeBlock.cpp	2021-12-08 20:27:32 UTC (rev 286702)
+++ trunk/Source/_javascript_Core/wasm/WasmCodeBlock.cpp	2021-12-08 20:27:51 UTC (rev 286703)
@@ -37,10 +37,30 @@
 
 Ref<CodeBlock> CodeBlock::create(Context* context, MemoryMode mode, ModuleInformation& moduleInformation, RefPtr<LLIntCallees> llintCallees)
 {
-    auto* result = new (NotNull, fastMalloc(sizeof(CodeBlock))) CodeBlock(context, mode, moduleInformation, llintCallees);
-    return adoptRef(*result);
+    return adoptRef(*new CodeBlock(context, mode, moduleInformation, llintCallees));
 }
 
+Ref<CodeBlock> CodeBlock::createFromExisting(MemoryMode mode, const CodeBlock& other)
+{
+    return adoptRef(*new CodeBlock(mode, other));
+}
+
+CodeBlock::CodeBlock(MemoryMode mode, const CodeBlock& other)
+    : m_calleeCount(other.m_calleeCount)
+    , m_mode(mode)
+    , m_llintCallees(other.m_llintCallees)
+    , m_embedderCallees(other.m_embedderCallees)
+    , m_wasmIndirectCallEntryPoints(other.m_wasmIndirectCallEntryPoints)
+    , m_wasmToWasmCallsites(other.m_wasmToWasmCallsites)
+    , m_wasmToWasmExitStubs(other.m_wasmToWasmExitStubs)
+{
+#if ENABLE(WEBASSEMBLY_B3JIT)
+    m_bbqCallees.resize(m_calleeCount);
+    m_omgCallees.resize(m_calleeCount);
+#endif
+    setCompilationFinished();
+}
+
 CodeBlock::CodeBlock(Context* context, MemoryMode mode, ModuleInformation& moduleInformation, RefPtr<LLIntCallees> llintCallees)
     : m_calleeCount(moduleInformation.internalFunctionCount())
     , m_mode(mode)

Modified: trunk/Source/_javascript_Core/wasm/WasmCodeBlock.h (286702 => 286703)


--- trunk/Source/_javascript_Core/wasm/WasmCodeBlock.h	2021-12-08 20:27:32 UTC (rev 286702)
+++ trunk/Source/_javascript_Core/wasm/WasmCodeBlock.h	2021-12-08 20:27:51 UTC (rev 286703)
@@ -54,6 +54,7 @@
     typedef void CallbackType(Ref<CodeBlock>&&);
     using AsyncCompilationCallback = RefPtr<WTF::SharedTask<CallbackType>>;
     static Ref<CodeBlock> create(Context*, MemoryMode, ModuleInformation&, RefPtr<LLIntCallees>);
+    static Ref<CodeBlock> createFromExisting(MemoryMode, const CodeBlock&);
 
     void waitUntilFinished();
     void compileAsync(Context*, AsyncCompilationCallback&&);
@@ -137,6 +138,7 @@
 #endif
 
     CodeBlock(Context*, MemoryMode, ModuleInformation&, RefPtr<LLIntCallees>);
+    CodeBlock(MemoryMode, const CodeBlock&);
     void setCompilationFinished();
     unsigned m_calleeCount;
     MemoryMode m_mode;

Modified: trunk/Source/_javascript_Core/wasm/WasmInstance.h (286702 => 286703)


--- trunk/Source/_javascript_Core/wasm/WasmInstance.h	2021-12-08 20:27:32 UTC (rev 286702)
+++ trunk/Source/_javascript_Core/wasm/WasmInstance.h	2021-12-08 20:27:51 UTC (rev 286703)
@@ -56,10 +56,9 @@
 
     static Ref<Instance> create(Context*, Ref<Module>&&, EntryFrame** pointerToTopEntryFrame, void** pointerToActualStackLimit, StoreTopCallFrameCallback&&);
 
-    void finalizeCreation(void* owner, Ref<CodeBlock>&& codeBlock)
+    void finalizeCreation(void* owner)
     {
         m_owner = owner;
-        m_codeBlock = WTFMove(codeBlock);
     }
 
     JS_EXPORT_PRIVATE ~Instance();
@@ -71,9 +70,9 @@
 
     Wasm::Context* context() const { return m_context; }
 
-    Module& module() { return m_module.get(); }
-    CodeBlock* codeBlock() { return m_codeBlock.get(); }
-    Memory* memory() { return m_memory.get(); }
+    Module& module() const { return m_module.get(); }
+    CodeBlock* codeBlock() const { return module().codeBlockFor(memory()->mode()); }
+    Memory* memory() const { return m_memory.get(); }
     Table* table(unsigned);
     void setTable(unsigned, Ref<Table>&&);
     const Element* elementAt(unsigned) const;
@@ -82,7 +81,7 @@
 
     bool isImportFunction(uint32_t functionIndex) const
     {
-        return functionIndex < m_codeBlock->functionImportCount();
+        return functionIndex < codeBlock()->functionImportCount();
     }
 
     void tableInit(uint32_t dstOffset, uint32_t srcOffset, uint32_t length, uint32_t elementIndex, uint32_t tableIndex);
@@ -226,7 +225,6 @@
     CagedPtr<Gigacage::Primitive, void, tagCagedPtr> m_cachedMemory;
     size_t m_cachedBoundsCheckingSize { 0 };
     Ref<Module> m_module;
-    RefPtr<CodeBlock> m_codeBlock;
     RefPtr<Memory> m_memory;
 
     MallocPtr<Global::Value, VMMalloc> m_globals;

Modified: trunk/Source/_javascript_Core/wasm/WasmModule.cpp (286702 => 286703)


--- trunk/Source/_javascript_Core/wasm/WasmModule.cpp	2021-12-08 20:27:32 UTC (rev 286702)
+++ trunk/Source/_javascript_Core/wasm/WasmModule.cpp	2021-12-08 20:27:51 UTC (rev 286703)
@@ -111,6 +111,18 @@
     codeBlock->compileAsync(context, WTFMove(task));
 }
 
+void Module::copyInitialCodeBlockToAllMemoryModes(MemoryMode initialMode)
+{
+    ASSERT(m_codeBlocks[static_cast<uint8_t>(initialMode)]);
+    const CodeBlock& initialBlock = *m_codeBlocks[static_cast<uint8_t>(initialMode)];
+    for (unsigned i = 0; i < Wasm::NumberOfMemoryModes; i++) {
+        if (i == static_cast<uint8_t>(initialMode))
+            continue;
+        Ref<CodeBlock> newBlock = CodeBlock::createFromExisting(static_cast<MemoryMode>(i), initialBlock);
+        m_codeBlocks[i] = WTFMove(newBlock);
+    }
+}
+
 } } // namespace JSC::Wasm
 
 #endif // ENABLE(WEBASSEMBLY)

Modified: trunk/Source/_javascript_Core/wasm/WasmModule.h (286702 => 286703)


--- trunk/Source/_javascript_Core/wasm/WasmModule.h	2021-12-08 20:27:32 UTC (rev 286702)
+++ trunk/Source/_javascript_Core/wasm/WasmModule.h	2021-12-08 20:27:51 UTC (rev 286703)
@@ -65,6 +65,9 @@
     JS_EXPORT_PRIVATE ~Module();
 
     CodeBlock* codeBlockFor(MemoryMode mode) { return m_codeBlocks[static_cast<uint8_t>(mode)].get(); }
+
+    void copyInitialCodeBlockToAllMemoryModes(MemoryMode);
+
 private:
     Ref<CodeBlock> getOrCreateCodeBlock(Context*, MemoryMode);
 

Modified: trunk/Source/_javascript_Core/wasm/js/JSWebAssembly.cpp (286702 => 286703)


--- trunk/Source/_javascript_Core/wasm/js/JSWebAssembly.cpp	2021-12-08 20:27:32 UTC (rev 286702)
+++ trunk/Source/_javascript_Core/wasm/js/JSWebAssembly.cpp	2021-12-08 20:27:51 UTC (rev 286703)
@@ -190,6 +190,7 @@
 {
     auto scope = DECLARE_THROW_SCOPE(vm);
     // In order to avoid potentially recompiling a module. We first gather all the import/memory information prior to compiling code.
+    // When called via the module loader, the memory is not available yet at this step, so we skip initializing the memory here.
     JSWebAssemblyInstance* instance = JSWebAssemblyInstance::tryCreate(vm, globalObject, moduleKey, module, importObject, globalObject->webAssemblyInstanceStructure(), Ref<Wasm::Module>(module->module()), creationMode);
     if (UNLIKELY(scope.exception())) {
         promise->rejectWithCaughtException(globalObject, scope);

Modified: trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyInstance.cpp (286702 => 286703)


--- trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyInstance.cpp	2021-12-08 20:27:32 UTC (rev 286702)
+++ trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyInstance.cpp	2021-12-08 20:27:51 UTC (rev 286703)
@@ -107,7 +107,7 @@
 
 void JSWebAssemblyInstance::finalizeCreation(VM& vm, JSGlobalObject* globalObject, Ref<Wasm::CodeBlock>&& wasmCodeBlock, JSObject* importObject, Wasm::CreationMode creationMode)
 {
-    m_instance->finalizeCreation(this, wasmCodeBlock.copyRef());
+    m_instance->finalizeCreation(this);
 
     auto scope = DECLARE_THROW_SCOPE(vm);
 
@@ -135,6 +135,29 @@
         m_module->setCodeBlock(vm, memoryMode(), jsCodeBlock);
     }
 
+    // In the module loader case, we will initialize all memory modes with the initial LLInt compilation
+    // results, so that later when memory imports become available, the appropriate CodeBlock can be used.
+    // If LLInt is disabled, we instead defer compilation to module evaluation.
+    bool hasMemoryImport = module()->moduleInformation().memory.isImport();
+    if (creationMode == Wasm::CreationMode::FromModuleLoader && Options::useWasmLLInt() && hasMemoryImport) {
+        Wasm::MemoryMode initialMode = Wasm::MemoryMode::BoundsChecking;
+        ASSERT(memoryMode() == initialMode);
+        module()->module().copyInitialCodeBlockToAllMemoryModes(initialMode);
+
+        for (unsigned i = 0; i < Wasm::NumberOfMemoryModes; i++) {
+            if (i == static_cast<uint8_t>(initialMode))
+                continue;
+            Wasm::MemoryMode memoryMode = static_cast<Wasm::MemoryMode>(i);
+            RefPtr<Wasm::CodeBlock> codeBlock = module()->module().codeBlockFor(memoryMode);
+            jsCodeBlock = JSWebAssemblyCodeBlock::create(vm, codeBlock.releaseNonNull(), module()->module().moduleInformation());
+            if (UNLIKELY(!jsCodeBlock->runnable())) {
+                throwException(globalObject, scope, createJSWebAssemblyLinkError(globalObject, vm, jsCodeBlock->errorMessage()));
+                return;
+            }
+            m_module->setCodeBlock(vm, memoryMode, jsCodeBlock);
+        }
+    }
+
     for (unsigned importFunctionNum = 0; importFunctionNum < instance().numImportFunctions(); ++importFunctionNum) {
         auto* info = instance().importFunctionInfo(importFunctionNum);
         info->wasmToEmbedderStub = m_codeBlock->wasmToEmbedderStub(importFunctionNum);
@@ -212,8 +235,8 @@
             Identifier::fromUid(PrivateName(PrivateName::Description, "WebAssemblyImportName")),
         });
 
-        // Skip Wasm::ExternalKind::Function validation here. It will be done in WebAssemblyModuleRecord::link.
-        // Eventually we will move all the linking code here to WebAssemblyModuleRecord::link.
+        // Validation for most types are done in WebAssemblyModuleRecord::initializeImportsAndExports and skipped here.
+        // Eventually we will move all the linking code here to WebAssemblyModuleRecord::initializeImportsAndExports.
         switch (import.kind) {
         case Wasm::ExternalKind::Function:
         case Wasm::ExternalKind::Global:
@@ -253,6 +276,10 @@
             RELEASE_ASSERT(!hasMemoryImport); // This should be guaranteed by a validation failure.
             RELEASE_ASSERT(moduleInformation.memory);
             hasMemoryImport = true;
+            // For the module loader, we cannot initialize the memory here so we delay this
+            // until WebAssemblyModuleRecord's initialization operation.
+            if (creationMode == Wasm::CreationMode::FromModuleLoader)
+                break;
             JSWebAssemblyMemory* memory = jsDynamicCast<JSWebAssemblyMemory*>(vm, value);
             // i. If v is not a WebAssembly.Memory object, throw a WebAssembly.LinkError.
             if (!memory)

Modified: trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyInstance.h (286702 => 286703)


--- trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyInstance.h	2021-12-08 20:27:32 UTC (rev 286702)
+++ trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyInstance.h	2021-12-08 20:27:51 UTC (rev 286703)
@@ -75,7 +75,6 @@
 
     JSWebAssemblyMemory* memory() { return m_memory.get(); }
     void setMemory(VM& vm, JSWebAssemblyMemory* value) {
-        ASSERT(!memory());
         m_memory.set(vm, this, value);
         instance().setMemory(memory()->memory());
     }

Modified: trunk/Source/_javascript_Core/wasm/js/WebAssemblyModuleRecord.cpp (286702 => 286703)


--- trunk/Source/_javascript_Core/wasm/js/WebAssemblyModuleRecord.cpp	2021-12-08 20:27:32 UTC (rev 286702)
+++ trunk/Source/_javascript_Core/wasm/js/WebAssemblyModuleRecord.cpp	2021-12-08 20:27:51 UTC (rev 286703)
@@ -121,7 +121,6 @@
 
     RELEASE_ASSERT(m_instance);
 
-    Wasm::CodeBlock* codeBlock = m_instance->instance().codeBlock();
     JSWebAssemblyModule* module = m_instance->module();
     const Wasm::ModuleInformation& moduleInformation = module->moduleInformation();
 
@@ -143,7 +142,9 @@
         case Wasm::ExternalKind::Exception:
             break;
         case Wasm::ExternalKind::Memory:
-            continue;
+            if (creationMode == Wasm::CreationMode::FromJS)
+                continue;
+            break;
         }
 
         Identifier moduleName = Identifier::fromString(vm, String::fromUTF8(import.module));
@@ -408,7 +409,46 @@
             break;
         }
 
+        // Memory initialization will only occur here if the creation mode was through the module loader.
         case Wasm::ExternalKind::Memory:
+            JSWebAssemblyMemory* memory = jsDynamicCast<JSWebAssemblyMemory*>(vm, value);
+            // i. If v is not a WebAssembly.Memory object, throw a WebAssembly.LinkError.
+            if (!memory)
+                return exception(createJSWebAssemblyLinkError(globalObject, vm, importFailMessage(import, "Memory import", "is not an instance of WebAssembly.Memory")));
+
+            Wasm::PageCount declaredInitial = moduleInformation.memory.initial();
+            Wasm::PageCount importedInitial = memory->memory().initial();
+            if (importedInitial < declaredInitial)
+                return exception(createJSWebAssemblyLinkError(globalObject, vm, importFailMessage(import, "Memory import", "provided an 'initial' that is smaller than the module's declared 'initial' import memory size")));
+
+            if (Wasm::PageCount declaredMaximum = moduleInformation.memory.maximum()) {
+                Wasm::PageCount importedMaximum = memory->memory().maximum();
+                if (!importedMaximum)
+                    return exception(createJSWebAssemblyLinkError(globalObject, vm, importFailMessage(import, "Memory import", "did not have a 'maximum' but the module requires that it does")));
+
+                if (importedMaximum > declaredMaximum)
+                    return exception(createJSWebAssemblyLinkError(globalObject, vm, importFailMessage(import, "Memory import", "provided a 'maximum' that is larger than the module's declared 'maximum' import memory size")));
+            }
+
+            if ((memory->memory().sharingMode() == Wasm::MemorySharingMode::Shared) != moduleInformation.memory.isShared())
+                return exception(createJSWebAssemblyLinkError(globalObject, vm, importFailMessage(import, "Memory import", "provided a 'shared' that is different from the module's declared 'shared' import memory attribute")));
+
+            // ii. Append v to memories.
+            // iii. Append v.[[Memory]] to imports.
+            m_instance->setMemory(vm, memory);
+            RETURN_IF_EXCEPTION(scope, void());
+
+            // Usually at this point the module's code block in any memory mode should be
+            // runnable due to the LLint tier code being shared among all modes. However,
+            // if LLInt is disabled, it is possible that the code needs to be compiled at
+            // this point when we know which memory mode to use.
+            Wasm::CodeBlock* codeBlock = m_instance->instance().codeBlock();
+            if (!codeBlock || !codeBlock->runnable()) {
+                codeBlock = m_instance->module()->module().compileSync(&vm.wasmContext, memory->memory().mode()).ptr();
+                if (!codeBlock->runnable())
+                    return exception(createJSWebAssemblyLinkError(globalObject, vm, codeBlock->errorMessage()));
+            }
+            RELEASE_ASSERT(codeBlock->isSafeToRun(memory->memory().mode()));
             break;
         }
     }
@@ -435,6 +475,9 @@
         }
     }
 
+    // This needs to be looked up after the memory is initialized, as the codeBlock depends on the memory mode.
+    Wasm::CodeBlock* codeBlock = m_instance->instance().codeBlock();
+
     for (Wasm::SignatureIndex signatureIndex : moduleInformation.internalExceptionSignatureIndices)
         m_instance->instance().addTag(Wasm::Tag::create(Wasm::SignatureInformation::get(signatureIndex)));
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to