[WebAssembly][Modules] Prototype wasm import
authorutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 17 Apr 2018 02:38:59 +0000 (02:38 +0000)
committerutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 17 Apr 2018 02:38:59 +0000 (02:38 +0000)
https://bugs.webkit.org/show_bug.cgi?id=184600

Reviewed by JF Bastien.

JSTests:

Add wasm and wat files since module loader want to load wasm files from FS.
Currently, importing the other modules from wasm is not supported.

* wasm.yaml:
* wasm/modules/constant.wasm: Added.
* wasm/modules/constant.wat: Added.
* wasm/modules/js-wasm-function-namespace.js: Added.
(assert.throws):
* wasm/modules/js-wasm-function.js: Added.
(assert.throws):
* wasm/modules/js-wasm-global-namespace.js: Added.
(assert.throws):
* wasm/modules/js-wasm-global.js: Added.
(assert.throws):
* wasm/modules/js-wasm-memory-namespace.js: Added.
(assert.throws):
* wasm/modules/js-wasm-memory.js: Added.
(assert.throws):
* wasm/modules/js-wasm-start.js: Added.
(then):
* wasm/modules/js-wasm-table-namespace.js: Added.
(assert.throws):
* wasm/modules/js-wasm-table.js: Added.
(assert.throws):
* wasm/modules/memory.wasm: Added.
* wasm/modules/memory.wat: Added.
* wasm/modules/start.wasm: Added.
* wasm/modules/start.wat: Added.
* wasm/modules/sum.wasm: Added.
* wasm/modules/sum.wat: Added.
* wasm/modules/table.wasm: Added.
* wasm/modules/table.wat: Added.

Source/JavaScriptCore:

This patch is an initial attempt to implement Wasm loading in module pipeline.
Currently,

1. We only support Wasm loading in the JSC shell. Once loading mechanism is specified
   in whatwg HTML, we should integrate this into WebCore.

2. We only support exporting values from Wasm. Wasm module cannot import anything from
   the other modules now.

When loading a file, JSC shell checks wasm magic. If the wasm magic is found, JSC shell
loads the file with WebAssemblySourceProvider. It is wrapped into JSSourceCode and
module loader pipeline just handles it as the same to JS. When parsing a module, we
checks the type of JSSourceCode. If the source code is Wasm source code, we create a
WebAssemblyModuleRecord instead of JSModuleRecord. Our module pipeline handles
AbstractModuleRecord and Wasm module is instantiated, linked, and evaluated.

* builtins/ModuleLoaderPrototype.js:
(globalPrivate.newRegistryEntry):
(requestInstantiate):
(link):
* jsc.cpp:
(convertShebangToJSComment):
(fillBufferWithContentsOfFile):
(fetchModuleFromLocalFileSystem):
(GlobalObject::moduleLoaderFetch):
* parser/SourceProvider.h:
(JSC::WebAssemblySourceProvider::create):
(JSC::WebAssemblySourceProvider::WebAssemblySourceProvider):
* runtime/AbstractModuleRecord.cpp:
(JSC::AbstractModuleRecord::hostResolveImportedModule):
(JSC::AbstractModuleRecord::link):
(JSC::AbstractModuleRecord::evaluate):
(JSC::identifierToJSValue): Deleted.
* runtime/AbstractModuleRecord.h:
* runtime/JSModuleLoader.cpp:
(JSC::JSModuleLoader::evaluate):
* runtime/JSModuleRecord.cpp:
(JSC::JSModuleRecord::link):
(JSC::JSModuleRecord::instantiateDeclarations):
* runtime/JSModuleRecord.h:
* runtime/ModuleLoaderPrototype.cpp:
(JSC::moduleLoaderPrototypeParseModule):
(JSC::moduleLoaderPrototypeRequestedModules):
(JSC::moduleLoaderPrototypeModuleDeclarationInstantiation):
* wasm/js/JSWebAssemblyHelpers.h:
(JSC::getWasmBufferFromValue):
(JSC::createSourceBufferFromValue):
* wasm/js/JSWebAssemblyInstance.cpp:
(JSC::JSWebAssemblyInstance::finalizeCreation):
(JSC::JSWebAssemblyInstance::createPrivateModuleKey):
(JSC::JSWebAssemblyInstance::create):
* wasm/js/JSWebAssemblyInstance.h:
* wasm/js/WebAssemblyInstanceConstructor.cpp:
(JSC::constructJSWebAssemblyInstance):
* wasm/js/WebAssemblyModuleRecord.cpp:
(JSC::WebAssemblyModuleRecord::prepareLink):
(JSC::WebAssemblyModuleRecord::link):
* wasm/js/WebAssemblyModuleRecord.h:
* wasm/js/WebAssemblyPrototype.cpp:
(JSC::resolve):
(JSC::instantiate):
(JSC::compileAndInstantiate):
(JSC::WebAssemblyPrototype::instantiate):
(JSC::webAssemblyInstantiateFunc):
(JSC::webAssemblyValidateFunc):
* wasm/js/WebAssemblyPrototype.h:

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

39 files changed:
JSTests/ChangeLog
JSTests/wasm.yaml
JSTests/wasm/modules/constant.wasm [new file with mode: 0644]
JSTests/wasm/modules/constant.wat [new file with mode: 0644]
JSTests/wasm/modules/js-wasm-function-namespace.js [new file with mode: 0644]
JSTests/wasm/modules/js-wasm-function.js [new file with mode: 0644]
JSTests/wasm/modules/js-wasm-global-namespace.js [new file with mode: 0644]
JSTests/wasm/modules/js-wasm-global.js [new file with mode: 0644]
JSTests/wasm/modules/js-wasm-memory-namespace.js [new file with mode: 0644]
JSTests/wasm/modules/js-wasm-memory.js [new file with mode: 0644]
JSTests/wasm/modules/js-wasm-start.js [new file with mode: 0644]
JSTests/wasm/modules/js-wasm-table-namespace.js [new file with mode: 0644]
JSTests/wasm/modules/js-wasm-table.js [new file with mode: 0644]
JSTests/wasm/modules/memory.wasm [new file with mode: 0644]
JSTests/wasm/modules/memory.wat [new file with mode: 0644]
JSTests/wasm/modules/start.wasm [new file with mode: 0644]
JSTests/wasm/modules/start.wat [new file with mode: 0644]
JSTests/wasm/modules/sum.wasm [new file with mode: 0644]
JSTests/wasm/modules/sum.wat [new file with mode: 0644]
JSTests/wasm/modules/table.wasm [new file with mode: 0644]
JSTests/wasm/modules/table.wat [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/builtins/ModuleLoaderPrototype.js
Source/JavaScriptCore/jsc.cpp
Source/JavaScriptCore/parser/SourceProvider.h
Source/JavaScriptCore/runtime/AbstractModuleRecord.cpp
Source/JavaScriptCore/runtime/AbstractModuleRecord.h
Source/JavaScriptCore/runtime/JSModuleLoader.cpp
Source/JavaScriptCore/runtime/JSModuleRecord.cpp
Source/JavaScriptCore/runtime/JSModuleRecord.h
Source/JavaScriptCore/runtime/ModuleLoaderPrototype.cpp
Source/JavaScriptCore/wasm/js/JSWebAssemblyHelpers.h
Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.cpp
Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.h
Source/JavaScriptCore/wasm/js/WebAssemblyInstanceConstructor.cpp
Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp
Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.h
Source/JavaScriptCore/wasm/js/WebAssemblyPrototype.cpp
Source/JavaScriptCore/wasm/js/WebAssemblyPrototype.h

index a3a2643fcc93abeeb58f6b222901779f2e40b78d..ea71c1b0e2ce872679c39a6a4788788d86f4b447 100644 (file)
@@ -1,3 +1,43 @@
+2018-04-16  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        [WebAssembly][Modules] Prototype wasm import
+        https://bugs.webkit.org/show_bug.cgi?id=184600
+
+        Reviewed by JF Bastien.
+
+        Add wasm and wat files since module loader want to load wasm files from FS.
+        Currently, importing the other modules from wasm is not supported.
+
+        * wasm.yaml:
+        * wasm/modules/constant.wasm: Added.
+        * wasm/modules/constant.wat: Added.
+        * wasm/modules/js-wasm-function-namespace.js: Added.
+        (assert.throws):
+        * wasm/modules/js-wasm-function.js: Added.
+        (assert.throws):
+        * wasm/modules/js-wasm-global-namespace.js: Added.
+        (assert.throws):
+        * wasm/modules/js-wasm-global.js: Added.
+        (assert.throws):
+        * wasm/modules/js-wasm-memory-namespace.js: Added.
+        (assert.throws):
+        * wasm/modules/js-wasm-memory.js: Added.
+        (assert.throws):
+        * wasm/modules/js-wasm-start.js: Added.
+        (then):
+        * wasm/modules/js-wasm-table-namespace.js: Added.
+        (assert.throws):
+        * wasm/modules/js-wasm-table.js: Added.
+        (assert.throws):
+        * wasm/modules/memory.wasm: Added.
+        * wasm/modules/memory.wat: Added.
+        * wasm/modules/start.wasm: Added.
+        * wasm/modules/start.wat: Added.
+        * wasm/modules/sum.wasm: Added.
+        * wasm/modules/sum.wat: Added.
+        * wasm/modules/table.wasm: Added.
+        * wasm/modules/table.wat: Added.
+
 2018-04-14  Filip Pizlo  <fpizlo@apple.com>
 
         Function.prototype.caller shouldn't return generator bodies
index f2124efb1a339d74133d9deacec4faab404644d8..87c88029a7a5501cd560c541daa8e1933da83988 100644 (file)
@@ -37,6 +37,8 @@
   cmd: runWebAssemblyLowExecutableMemory unless parseRunCommands
 - path: wasm/regress/
   cmd: runWebAssembly unless parseRunCommands
+- path: wasm/modules/
+  cmd: runWebAssembly unless parseRunCommands
 
 - path: wasm/spec-tests/address.wast.js
   cmd: runWebAssemblySpecTest :normal
diff --git a/JSTests/wasm/modules/constant.wasm b/JSTests/wasm/modules/constant.wasm
new file mode 100644 (file)
index 0000000..106abdf
Binary files /dev/null and b/JSTests/wasm/modules/constant.wasm differ
diff --git a/JSTests/wasm/modules/constant.wat b/JSTests/wasm/modules/constant.wat
new file mode 100644 (file)
index 0000000..d639245
--- /dev/null
@@ -0,0 +1,2 @@
+(module
+    (global $constant (export "constant") i32 i32.const 42))
diff --git a/JSTests/wasm/modules/js-wasm-function-namespace.js b/JSTests/wasm/modules/js-wasm-function-namespace.js
new file mode 100644 (file)
index 0000000..054db03
--- /dev/null
@@ -0,0 +1,11 @@
+import * as sum from "./sum.wasm"
+import * as assert from '../assert.js';
+
+assert.isObject(sum);
+assert.isFunction(sum.sum);
+assert.eq(sum.sum(32, 42), 74);
+assert.eq(sum.sum(-2, 42), 40);
+
+assert.throws(() => {
+    sum.sum = 32;
+}, TypeError, `Attempted to assign to readonly property.`);
diff --git a/JSTests/wasm/modules/js-wasm-function.js b/JSTests/wasm/modules/js-wasm-function.js
new file mode 100644 (file)
index 0000000..0be5b81
--- /dev/null
@@ -0,0 +1,10 @@
+import { sum } from "./sum.wasm"
+import * as assert from '../assert.js';
+
+assert.isFunction(sum);
+assert.eq(sum(32, 42), 74);
+assert.eq(sum(-2, 42), 40);
+
+assert.throws(() => {
+    sum = 32;
+}, TypeError, `Attempted to assign to readonly property.`);
diff --git a/JSTests/wasm/modules/js-wasm-global-namespace.js b/JSTests/wasm/modules/js-wasm-global-namespace.js
new file mode 100644 (file)
index 0000000..52a4dfa
--- /dev/null
@@ -0,0 +1,8 @@
+import * as constant from "./constant.wasm"
+import * as assert from '../assert.js';
+
+assert.isNumber(constant.constant);
+assert.eq(constant.constant, 42);
+assert.throws(() => {
+    constant.constant = 200;
+}, TypeError, `Attempted to assign to readonly property.`);
diff --git a/JSTests/wasm/modules/js-wasm-global.js b/JSTests/wasm/modules/js-wasm-global.js
new file mode 100644 (file)
index 0000000..5ae7929
--- /dev/null
@@ -0,0 +1,8 @@
+import { constant } from "./constant.wasm"
+import * as assert from '../assert.js';
+
+assert.isNumber(constant);
+assert.eq(constant, 42);
+assert.throws(() => {
+    constant = 200;
+}, TypeError, `Attempted to assign to readonly property.`);
diff --git a/JSTests/wasm/modules/js-wasm-memory-namespace.js b/JSTests/wasm/modules/js-wasm-memory-namespace.js
new file mode 100644 (file)
index 0000000..bd32e3a
--- /dev/null
@@ -0,0 +1,12 @@
+import * as memory from "./memory.wasm"
+import * as assert from '../assert.js';
+
+assert.instanceof(memory.memory, WebAssembly.Memory);
+let buffer = new Uint8Array(memory.memory.buffer);
+assert.eq(buffer[4], 0x10);
+assert.eq(buffer[5], 0x00);
+assert.eq(buffer[6], 0x10);
+assert.eq(buffer[7], 0x00);
+assert.throws(() => {
+    memory.memory = 200;
+}, TypeError, `Attempted to assign to readonly property.`);
diff --git a/JSTests/wasm/modules/js-wasm-memory.js b/JSTests/wasm/modules/js-wasm-memory.js
new file mode 100644 (file)
index 0000000..ed5eccf
--- /dev/null
@@ -0,0 +1,12 @@
+import { memory } from "./memory.wasm"
+import * as assert from '../assert.js';
+
+assert.instanceof(memory, WebAssembly.Memory);
+let buffer = new Uint8Array(memory.buffer);
+assert.eq(buffer[4], 0x10);
+assert.eq(buffer[5], 0x00);
+assert.eq(buffer[6], 0x10);
+assert.eq(buffer[7], 0x00);
+assert.throws(() => {
+    memory = 200;
+}, TypeError, `Attempted to assign to readonly property.`);
diff --git a/JSTests/wasm/modules/js-wasm-start.js b/JSTests/wasm/modules/js-wasm-start.js
new file mode 100644 (file)
index 0000000..c2274c0
--- /dev/null
@@ -0,0 +1,9 @@
+import * as assert from '../assert.js';
+
+Promise.all([
+    import("./start.wasm"),
+    import("./start.wasm"),
+]).then(([start0, start1]) => {
+    assert.eq(start0, start1);
+    assert.eq(start0.get(), 1);
+}, $vm.abort);
diff --git a/JSTests/wasm/modules/js-wasm-table-namespace.js b/JSTests/wasm/modules/js-wasm-table-namespace.js
new file mode 100644 (file)
index 0000000..a9cc3ba
--- /dev/null
@@ -0,0 +1,15 @@
+import * as table from "./table.wasm"
+import * as assert from '../assert.js';
+
+assert.instanceof(table.table, WebAssembly.Table);
+assert.eq(table.table.length, 3);
+assert.isFunction(table.table.get(0));
+assert.isFunction(table.table.get(1));
+assert.eq(table.table.get(2), null);
+
+assert.eq(table.table.get(0)(), 42);
+assert.eq(table.table.get(1)(), 83);
+
+assert.throws(() => {
+    table.table = 32;
+}, TypeError, `Attempted to assign to readonly property.`);
diff --git a/JSTests/wasm/modules/js-wasm-table.js b/JSTests/wasm/modules/js-wasm-table.js
new file mode 100644 (file)
index 0000000..a27f51c
--- /dev/null
@@ -0,0 +1,15 @@
+import { table } from "./table.wasm"
+import * as assert from '../assert.js';
+
+assert.instanceof(table, WebAssembly.Table);
+assert.eq(table.length, 3);
+assert.isFunction(table.get(0));
+assert.isFunction(table.get(1));
+assert.eq(table.get(2), null);
+
+assert.eq(table.get(0)(), 42);
+assert.eq(table.get(1)(), 83);
+
+assert.throws(() => {
+    table = 32;
+}, TypeError, `Attempted to assign to readonly property.`);
diff --git a/JSTests/wasm/modules/memory.wasm b/JSTests/wasm/modules/memory.wasm
new file mode 100644 (file)
index 0000000..fb69610
Binary files /dev/null and b/JSTests/wasm/modules/memory.wasm differ
diff --git a/JSTests/wasm/modules/memory.wat b/JSTests/wasm/modules/memory.wat
new file mode 100644 (file)
index 0000000..27a3b11
--- /dev/null
@@ -0,0 +1,3 @@
+(module
+    (memory $memory (export "memory") 17)
+    (data (i32.const 4) "\10\00\10\00"))
diff --git a/JSTests/wasm/modules/start.wasm b/JSTests/wasm/modules/start.wasm
new file mode 100644 (file)
index 0000000..771660f
Binary files /dev/null and b/JSTests/wasm/modules/start.wasm differ
diff --git a/JSTests/wasm/modules/start.wat b/JSTests/wasm/modules/start.wat
new file mode 100644 (file)
index 0000000..7744e42
--- /dev/null
@@ -0,0 +1,12 @@
+(module
+    (global $g0 (mut i32) i32.const 0)
+    (type $t0 (func))
+    (func $increment (type $t0)
+        get_global $g0
+        i32.const 1
+        i32.add
+        set_global $g0)
+    (start $increment)
+    (type $t1 (func (result i32)))
+    (func $get (export "get") (type $t1) (result i32)
+        get_global $g0))
diff --git a/JSTests/wasm/modules/sum.wasm b/JSTests/wasm/modules/sum.wasm
new file mode 100644 (file)
index 0000000..4c722a7
Binary files /dev/null and b/JSTests/wasm/modules/sum.wasm differ
diff --git a/JSTests/wasm/modules/sum.wat b/JSTests/wasm/modules/sum.wat
new file mode 100644 (file)
index 0000000..ba3f2a3
--- /dev/null
@@ -0,0 +1,6 @@
+(module
+    (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
+        get_local $p0
+        i32.add))
diff --git a/JSTests/wasm/modules/table.wasm b/JSTests/wasm/modules/table.wasm
new file mode 100644 (file)
index 0000000..7408c46
Binary files /dev/null and b/JSTests/wasm/modules/table.wasm differ
diff --git a/JSTests/wasm/modules/table.wat b/JSTests/wasm/modules/table.wat
new file mode 100644 (file)
index 0000000..6a6b699
--- /dev/null
@@ -0,0 +1,5 @@
+(module
+    (table $table (export "table") 3 anyfunc)
+    (func $f0 (result i32) i32.const 42)
+    (func $f1 (result i32) i32.const 83)
+    (elem (i32.const 0) $f0 $f1))
index 4f1d38a9bf0dc96161333e8480a55ee3ff984502..ad0ced6e4de53f8fe39f587e7057c933bbbcc0f6 100644 (file)
@@ -1,3 +1,77 @@
+2018-04-16  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        [WebAssembly][Modules] Prototype wasm import
+        https://bugs.webkit.org/show_bug.cgi?id=184600
+
+        Reviewed by JF Bastien.
+
+        This patch is an initial attempt to implement Wasm loading in module pipeline.
+        Currently,
+
+        1. We only support Wasm loading in the JSC shell. Once loading mechanism is specified
+           in whatwg HTML, we should integrate this into WebCore.
+
+        2. We only support exporting values from Wasm. Wasm module cannot import anything from
+           the other modules now.
+
+        When loading a file, JSC shell checks wasm magic. If the wasm magic is found, JSC shell
+        loads the file with WebAssemblySourceProvider. It is wrapped into JSSourceCode and
+        module loader pipeline just handles it as the same to JS. When parsing a module, we
+        checks the type of JSSourceCode. If the source code is Wasm source code, we create a
+        WebAssemblyModuleRecord instead of JSModuleRecord. Our module pipeline handles
+        AbstractModuleRecord and Wasm module is instantiated, linked, and evaluated.
+
+        * builtins/ModuleLoaderPrototype.js:
+        (globalPrivate.newRegistryEntry):
+        (requestInstantiate):
+        (link):
+        * jsc.cpp:
+        (convertShebangToJSComment):
+        (fillBufferWithContentsOfFile):
+        (fetchModuleFromLocalFileSystem):
+        (GlobalObject::moduleLoaderFetch):
+        * parser/SourceProvider.h:
+        (JSC::WebAssemblySourceProvider::create):
+        (JSC::WebAssemblySourceProvider::WebAssemblySourceProvider):
+        * runtime/AbstractModuleRecord.cpp:
+        (JSC::AbstractModuleRecord::hostResolveImportedModule):
+        (JSC::AbstractModuleRecord::link):
+        (JSC::AbstractModuleRecord::evaluate):
+        (JSC::identifierToJSValue): Deleted.
+        * runtime/AbstractModuleRecord.h:
+        * runtime/JSModuleLoader.cpp:
+        (JSC::JSModuleLoader::evaluate):
+        * runtime/JSModuleRecord.cpp:
+        (JSC::JSModuleRecord::link):
+        (JSC::JSModuleRecord::instantiateDeclarations):
+        * runtime/JSModuleRecord.h:
+        * runtime/ModuleLoaderPrototype.cpp:
+        (JSC::moduleLoaderPrototypeParseModule):
+        (JSC::moduleLoaderPrototypeRequestedModules):
+        (JSC::moduleLoaderPrototypeModuleDeclarationInstantiation):
+        * wasm/js/JSWebAssemblyHelpers.h:
+        (JSC::getWasmBufferFromValue):
+        (JSC::createSourceBufferFromValue):
+        * wasm/js/JSWebAssemblyInstance.cpp:
+        (JSC::JSWebAssemblyInstance::finalizeCreation):
+        (JSC::JSWebAssemblyInstance::createPrivateModuleKey):
+        (JSC::JSWebAssemblyInstance::create):
+        * wasm/js/JSWebAssemblyInstance.h:
+        * wasm/js/WebAssemblyInstanceConstructor.cpp:
+        (JSC::constructJSWebAssemblyInstance):
+        * wasm/js/WebAssemblyModuleRecord.cpp:
+        (JSC::WebAssemblyModuleRecord::prepareLink):
+        (JSC::WebAssemblyModuleRecord::link):
+        * wasm/js/WebAssemblyModuleRecord.h:
+        * wasm/js/WebAssemblyPrototype.cpp:
+        (JSC::resolve):
+        (JSC::instantiate):
+        (JSC::compileAndInstantiate):
+        (JSC::WebAssemblyPrototype::instantiate):
+        (JSC::webAssemblyInstantiateFunc):
+        (JSC::webAssemblyValidateFunc):
+        * wasm/js/WebAssemblyPrototype.h:
+
 2018-04-14  Filip Pizlo  <fpizlo@apple.com>
 
         Function.prototype.caller shouldn't return generator bodies
index 93f22256d673d6122080e0eb1f46e6dc315bce4b..eef91eb86551fa93197c14d80908dd69f56dc74a 100644 (file)
@@ -95,7 +95,6 @@ function newRegistryEntry(key)
         instantiate: @undefined,
         satisfy: @undefined,
         dependencies: [], // To keep the module order, we store the module keys in the array.
-        dependenciesMap: @undefined,
         module: @undefined, // JSModuleRecord
         linkError: @undefined,
         linkSucceeded: true,
@@ -197,22 +196,22 @@ function requestInstantiate(entry, parameters, fetcher)
         entry.instantiate = instantiatePromise;
 
         var key = entry.key;
-        var moduleRecord = this.parseModule(key, source);
-        var dependenciesMap = moduleRecord.dependenciesMap;
-        var requestedModules = this.requestedModules(moduleRecord);
-        var dependencies = @newArrayWithSize(requestedModules.length);
-        for (var i = 0, length = requestedModules.length; i < length; ++i) {
-            var depName = requestedModules[i];
-            var depKey = this.resolveSync(depName, key, fetcher);
-            var depEntry = this.ensureRegistered(depKey);
-            @putByValDirect(dependencies, i, depEntry);
-            dependenciesMap.@set(depName, depEntry);
-        }
-        entry.dependencies = dependencies;
-        entry.dependenciesMap = dependenciesMap;
-        entry.module = moduleRecord;
-        @setStateToMax(entry, @ModuleSatisfy);
-        return entry;
+        return this.parseModule(key, source).then((moduleRecord) => {
+            var dependenciesMap = moduleRecord.dependenciesMap;
+            var requestedModules = this.requestedModules(moduleRecord);
+            var dependencies = @newArrayWithSize(requestedModules.length);
+            for (var i = 0, length = requestedModules.length; i < length; ++i) {
+                var depName = requestedModules[i];
+                var depKey = this.resolveSync(depName, key, fetcher);
+                var depEntry = this.ensureRegistered(depKey);
+                @putByValDirect(dependencies, i, depEntry);
+                dependenciesMap.@set(depName, depEntry);
+            }
+            entry.dependencies = dependencies;
+            entry.module = moduleRecord;
+            @setStateToMax(entry, @ModuleSatisfy);
+            return entry;
+        });
     });
     return instantiatePromise;
 }
@@ -288,7 +287,7 @@ function link(entry, fetcher)
         for (var i = 0, length = dependencies.length; i < length; ++i)
             this.link(dependencies[i], fetcher);
 
-        this.moduleDeclarationInstantiation(entry.module, entry.key, fetcher);
+        this.moduleDeclarationInstantiation(entry.module, fetcher);
     } catch (error) {
         entry.linkSucceeded = false;
         entry.linkError = error;
index 40c7edc8f6e70b0a36a9b795755b6676852f9db2..10a44afe51895dce200befb82ebf8b66fe582c15 100644 (file)
@@ -186,7 +186,8 @@ static unsigned asyncTestExpectedPasses { 0 };
 
 }
 
-static bool fillBufferWithContentsOfFile(const String& fileName, Vector<char>& buffer);
+template<typename Vector>
+static bool fillBufferWithContentsOfFile(const String& fileName, Vector& buffer);
 static RefPtr<Uint8Array> fillBufferWithContentsOfFile(const String& fileName);
 
 class CommandLine;
@@ -844,7 +845,8 @@ Identifier GlobalObject::moduleLoaderResolve(JSGlobalObject* globalObject, ExecS
     return Identifier::fromString(&vm, resolvePath(directoryName.value(), ModuleName(key.impl())));
 }
 
-static void convertShebangToJSComment(Vector<char>& buffer)
+template<typename Vector>
+static void convertShebangToJSComment(Vector& buffer)
 {
     if (buffer.size() >= 2) {
         if (buffer[0] == '#' && buffer[1] == '!')
@@ -882,7 +884,8 @@ static RefPtr<Uint8Array> fillBufferWithContentsOfFile(const String& fileName)
     return result;
 }
 
-static bool fillBufferWithContentsOfFile(FILE* file, Vector<char>& buffer)
+template<typename Vector>
+static bool fillBufferWithContentsOfFile(FILE* file, Vector& buffer)
 {
     // We might have injected "use strict"; at the top.
     size_t initialSize = buffer.size();
@@ -920,7 +923,8 @@ static bool fetchScriptFromLocalFileSystem(const String& fileName, Vector<char>&
     return true;
 }
 
-static bool fetchModuleFromLocalFileSystem(const String& fileName, Vector<char>& buffer)
+template<typename Vector>
+static bool fetchModuleFromLocalFileSystem(const String& fileName, Vector& buffer)
 {
     // We assume that fileName is always an absolute path.
 #if OS(WINDOWS)
@@ -971,14 +975,25 @@ JSInternalPromise* GlobalObject::moduleLoaderFetch(JSGlobalObject* globalObject,
     }
 
     // Here, now we consider moduleKey as the fileName.
-    Vector<char> utf8;
-    if (!fetchModuleFromLocalFileSystem(moduleKey, utf8)) {
+    Vector<uint8_t> buffer;
+    if (!fetchModuleFromLocalFileSystem(moduleKey, buffer)) {
         auto result = deferred->reject(exec, createError(exec, makeString("Could not open file '", moduleKey, "'.")));
         scope.releaseAssertNoException();
         return result;
     }
 
-    auto result = deferred->resolve(exec, JSSourceCode::create(vm, makeSource(stringFromUTF(utf8), SourceOrigin { moduleKey }, moduleKey, TextPosition(), SourceProviderSourceType::Module)));
+#if ENABLE(WEBASSEMBLY)
+    // FileSystem does not have mime-type header. The JSC shell recognizes WebAssembly's magic header.
+    if (buffer.size() >= 4) {
+        if (buffer[0] == '\0' && buffer[1] == 'a' && buffer[2] == 's' && buffer[3] == 'm') {
+            auto result = deferred->resolve(exec, JSSourceCode::create(vm, SourceCode(WebAssemblySourceProvider::create(WTFMove(buffer), SourceOrigin { moduleKey }, moduleKey))));
+            scope.releaseAssertNoException();
+            return result;
+        }
+    }
+#endif
+
+    auto result = deferred->resolve(exec, JSSourceCode::create(vm, makeSource(stringFromUTF(buffer), SourceOrigin { moduleKey }, moduleKey, TextPosition(), SourceProviderSourceType::Module)));
     scope.releaseAssertNoException();
     return result;
 }
index 2e68e82027db28589f37b4f00f6cf880b4eafc82..0d0c2fc84cd05a58a31212a369af75a581a0122e 100644 (file)
@@ -120,9 +120,9 @@ namespace JSC {
 #if ENABLE(WEBASSEMBLY)
     class WebAssemblySourceProvider : public SourceProvider {
     public:
-        static Ref<WebAssemblySourceProvider> create(const Vector<uint8_t>& data, const SourceOrigin& sourceOrigin, const String& url)
+        static Ref<WebAssemblySourceProvider> create(Vector<uint8_t>&& data, const SourceOrigin& sourceOrigin, const String& url)
         {
-            return adoptRef(*new WebAssemblySourceProvider(data, sourceOrigin, url));
+            return adoptRef(*new WebAssemblySourceProvider(WTFMove(data), sourceOrigin, url));
         }
 
         unsigned hash() const override
@@ -141,10 +141,10 @@ namespace JSC {
         }
 
     private:
-        WebAssemblySourceProvider(const Vector<uint8_t>& data, const SourceOrigin& sourceOrigin, const String& url)
+        WebAssemblySourceProvider(Vector<uint8_t>&& data, const SourceOrigin& sourceOrigin, const String& url)
             : SourceProvider(sourceOrigin, url, TextPosition(), SourceProviderSourceType::WebAssembly)
             , m_source("[WebAssembly source]")
-            , m_data(data)
+            , m_data(WTFMove(data))
         {
         }
 
index 33253df596f70925224b3868bf8833fd09dcc481..2c8042dfed3ded4aa9118bd09bb1b741b0d506f9 100644 (file)
@@ -32,7 +32,9 @@
 #include "JSMap.h"
 #include "JSModuleEnvironment.h"
 #include "JSModuleNamespaceObject.h"
+#include "JSModuleRecord.h"
 #include "UnlinkedModuleProgramCodeBlock.h"
+#include "WebAssemblyModuleRecord.h"
 
 namespace JSC {
 namespace AbstractModuleRecordInternal {
@@ -137,19 +139,11 @@ auto AbstractModuleRecord::Resolution::ambiguous() -> Resolution
     return Resolution { Type::Ambiguous, nullptr, Identifier() };
 }
 
-static JSValue identifierToJSValue(ExecState* exec, const Identifier& identifier)
-{
-    VM& vm = exec->vm();
-    if (identifier.isSymbol())
-        return Symbol::create(vm, static_cast<SymbolImpl&>(*identifier.impl()));
-    return jsString(&vm, identifier.impl());
-}
-
 AbstractModuleRecord* AbstractModuleRecord::hostResolveImportedModule(ExecState* exec, const Identifier& moduleName)
 {
     VM& vm = exec->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
-    JSValue moduleNameValue = identifierToJSValue(exec, moduleName);
+    JSValue moduleNameValue = identifierToJSValue(vm, moduleName);
     JSValue entry = m_dependenciesMap->JSMap::get(exec, moduleNameValue);
     RETURN_IF_EXCEPTION(scope, nullptr);
     scope.release();
@@ -775,6 +769,31 @@ JSModuleNamespaceObject* AbstractModuleRecord::getModuleNamespace(ExecState* exe
     return moduleNamespaceObject;
 }
 
+void AbstractModuleRecord::link(ExecState* exec, JSValue scriptFetcher)
+{
+    VM& vm = exec->vm();
+    if (auto* jsModuleRecord = jsDynamicCast<JSModuleRecord*>(vm, this))
+        return jsModuleRecord->link(exec, scriptFetcher);
+#if ENABLE(WEBASSEMBLY)
+    if (auto* wasmModuleRecord = jsDynamicCast<WebAssemblyModuleRecord*>(vm, this))
+        return wasmModuleRecord->link(exec, scriptFetcher);
+#endif
+    RELEASE_ASSERT_NOT_REACHED();
+}
+
+JS_EXPORT_PRIVATE JSValue AbstractModuleRecord::evaluate(ExecState* exec)
+{
+    VM& vm = exec->vm();
+    if (auto* jsModuleRecord = jsDynamicCast<JSModuleRecord*>(vm, this))
+        return jsModuleRecord->evaluate(exec);
+#if ENABLE(WEBASSEMBLY)
+    if (auto* wasmModuleRecord = jsDynamicCast<WebAssemblyModuleRecord*>(vm, this))
+        return wasmModuleRecord->evaluate(exec);
+#endif
+    RELEASE_ASSERT_NOT_REACHED();
+    return jsUndefined();
+}
+
 static String printableName(const RefPtr<UniquedStringImpl>& uid)
 {
     if (uid->isSymbol())
index 592995b50619cbfe6cc2fada28b7e6c4ab280cb4..5588b2f03874e8f4c35b56b8a17edfd76886d899 100644 (file)
@@ -119,6 +119,9 @@ public:
         return m_moduleEnvironment.get();
     }
 
+    void link(ExecState*, JSValue scriptFetcher);
+    JS_EXPORT_PRIVATE JSValue evaluate(ExecState*);
+
 protected:
     AbstractModuleRecord(VM&, Structure*, const Identifier&);
     void finishCreation(ExecState*, VM&);
index 1be3c7ac386fbb17e6569f98e9f8f8448576b5d0..908591d9280c8df8d33f65cf33978b3278c00f05 100644 (file)
@@ -275,10 +275,9 @@ JSValue JSModuleLoader::evaluate(ExecState* exec, JSValue key, JSValue moduleRec
     if (globalObject->globalObjectMethodTable()->moduleLoaderEvaluate)
         return globalObject->globalObjectMethodTable()->moduleLoaderEvaluate(globalObject, exec, this, key, moduleRecordValue, scriptFetcher);
 
-    JSModuleRecord* moduleRecord = jsDynamicCast<JSModuleRecord*>(exec->vm(), moduleRecordValue);
-    if (!moduleRecord)
-        return jsUndefined();
-    return moduleRecord->evaluate(exec);
+    if (auto* moduleRecord = jsDynamicCast<AbstractModuleRecord*>(exec->vm(), moduleRecordValue))
+        return moduleRecord->evaluate(exec);
+    return jsUndefined();
 }
 
 JSModuleNamespaceObject* JSModuleLoader::getModuleNamespaceObject(ExecState* exec, JSValue moduleRecordValue)
index 6fa2f72ea2e728ecb481ebbbd6222fe43f529ad9..a7c99dcc4833060a9c3265bf34b5b1fe2598bb09 100644 (file)
@@ -78,7 +78,7 @@ void JSModuleRecord::visitChildren(JSCell* cell, SlotVisitor& visitor)
     visitor.append(thisObject->m_moduleProgramExecutable);
 }
 
-void JSModuleRecord::link(ExecState* exec, JSValue key, JSValue scriptFetcher)
+void JSModuleRecord::link(ExecState* exec, JSValue scriptFetcher)
 {
     VM& vm = exec->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
@@ -89,12 +89,12 @@ void JSModuleRecord::link(ExecState* exec, JSValue key, JSValue scriptFetcher)
         throwSyntaxError(exec, scope);
         return;
     }
-    instantiateDeclarations(exec, executable, key, scriptFetcher);
+    instantiateDeclarations(exec, executable, scriptFetcher);
     RETURN_IF_EXCEPTION(scope, void());
     m_moduleProgramExecutable.set(vm, this, executable);
 }
 
-void JSModuleRecord::instantiateDeclarations(ExecState* exec, ModuleProgramExecutable* moduleProgramExecutable, JSValue key, JSValue scriptFetcher)
+void JSModuleRecord::instantiateDeclarations(ExecState* exec, ModuleProgramExecutable* moduleProgramExecutable, JSValue scriptFetcher)
 {
     VM& vm = exec->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
@@ -208,7 +208,7 @@ void JSModuleRecord::instantiateDeclarations(ExecState* exec, ModuleProgramExecu
     }
 
     {
-        JSObject* metaProperties = exec->lexicalGlobalObject()->moduleLoader()->createImportMetaProperties(exec, key, this, scriptFetcher);
+        JSObject* metaProperties = exec->lexicalGlobalObject()->moduleLoader()->createImportMetaProperties(exec, identifierToJSValue(vm, moduleKey()), this, scriptFetcher);
         RETURN_IF_EXCEPTION(scope, void());
         bool putResult = false;
         symbolTablePutTouchWatchpointSet(moduleEnvironment, exec, vm.propertyNames->builtinNames().metaPrivateName(), metaProperties, /* shouldThrowReadOnlyError */ false, /* ignoreReadOnlyErrors */ true, putResult);
index cdfcc40ee5829e7257514f9817e99368070949bc..ac2dcfa6c5298bd73e4fdc2cf51f0cc15407bcfd 100644 (file)
@@ -45,7 +45,7 @@ public:
     static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
     static JSModuleRecord* create(ExecState*, VM&, Structure*, const Identifier&, const SourceCode&, const VariableEnvironment&, const VariableEnvironment&);
 
-    void link(ExecState*, JSValue key, JSValue scriptFetcher);
+    void link(ExecState*, JSValue scriptFetcher);
     JS_EXPORT_PRIVATE JSValue evaluate(ExecState*);
 
     const SourceCode& sourceCode() const { return m_sourceCode; }
@@ -60,7 +60,7 @@ private:
     static void visitChildren(JSCell*, SlotVisitor&);
     static void destroy(JSCell*);
 
-    void instantiateDeclarations(ExecState*, ModuleProgramExecutable*, JSValue key, JSValue scriptFetcher);
+    void instantiateDeclarations(ExecState*, ModuleProgramExecutable*, JSValue scriptFetcher);
 
     SourceCode m_sourceCode;
     VariableEnvironment m_declaredVariables;
index 3d4f44a14597ec1cc05bcf2c7264aa2eb547fae4..4e093e10aa5de4c6212576875bff18695e8d31a4 100644 (file)
@@ -45,6 +45,7 @@
 #include "Nodes.h"
 #include "Parser.h"
 #include "ParserError.h"
+#include "WebAssemblyPrototype.h"
 
 namespace JSC {
 
@@ -76,7 +77,7 @@ const ClassInfo ModuleLoaderPrototype::s_info = { "ModuleLoader", &Base::s_info,
     requestInstantiate             JSBuiltin                                           DontEnum|Function 3
     requestSatisfy                 JSBuiltin                                           DontEnum|Function 3
     link                           JSBuiltin                                           DontEnum|Function 2
-    moduleDeclarationInstantiation moduleLoaderPrototypeModuleDeclarationInstantiation DontEnum|Function 3
+    moduleDeclarationInstantiation moduleLoaderPrototypeModuleDeclarationInstantiation DontEnum|Function 2
     moduleEvaluation               JSBuiltin                                           DontEnum|Function 2
     evaluate                       moduleLoaderPrototypeEvaluate                       DontEnum|Function 3
     provideFetch                   JSBuiltin                                           DontEnum|Function 2
@@ -103,41 +104,52 @@ ModuleLoaderPrototype::ModuleLoaderPrototype(VM& vm, Structure* structure)
 EncodedJSValue JSC_HOST_CALL moduleLoaderPrototypeParseModule(ExecState* exec)
 {
     VM& vm = exec->vm();
-    auto scope = DECLARE_THROW_SCOPE(vm);
+    auto scope = DECLARE_CATCH_SCOPE(vm);
+
+    JSInternalPromiseDeferred* deferred = JSInternalPromiseDeferred::create(exec, exec->lexicalGlobalObject());
+    scope.releaseAssertNoException();
+
+    auto reject = [&] {
+        JSValue exception = scope.exception();
+        scope.clearException();
+        return JSValue::encode(deferred->reject(exec, exception));
+    };
 
     const Identifier moduleKey = exec->argument(0).toPropertyKey(exec);
-    RETURN_IF_EXCEPTION(scope, encodedJSValue());
+    if (UNLIKELY(scope.exception()))
+        return reject();
 
-    auto* jsSourceCode = jsDynamicCast<JSSourceCode*>(vm, exec->argument(1));
-    if (!jsSourceCode)
-        return throwVMTypeError(exec, scope);
+    JSValue source = exec->argument(1);
+    auto* jsSourceCode = jsCast<JSSourceCode*>(source);
     SourceCode sourceCode = jsSourceCode->sourceCode();
 
+#if ENABLE(WEBASSEMBLY)
+    if (sourceCode.provider()->sourceType() == SourceProviderSourceType::WebAssembly)
+        return JSValue::encode(WebAssemblyPrototype::instantiate(exec, deferred, moduleKey, jsSourceCode));
+#endif
+
     CodeProfiling profile(sourceCode);
 
     ParserError error;
     std::unique_ptr<ModuleProgramNode> moduleProgramNode = parse<ModuleProgramNode>(
         &vm, sourceCode, Identifier(), JSParserBuiltinMode::NotBuiltin,
         JSParserStrictMode::Strict, JSParserScriptMode::Module, SourceParseMode::ModuleAnalyzeMode, SuperBinding::NotNeeded, error);
-
-    if (error.isValid()) {
-        throwVMError(exec, scope, error.toErrorObject(exec->lexicalGlobalObject(), sourceCode));
-        return JSValue::encode(jsUndefined());
-    }
+    if (error.isValid())
+        return JSValue::encode(deferred->reject(exec, error.toErrorObject(exec->lexicalGlobalObject(), sourceCode)));
     ASSERT(moduleProgramNode);
 
     ModuleAnalyzer moduleAnalyzer(exec, moduleKey, sourceCode, moduleProgramNode->varDeclarations(), moduleProgramNode->lexicalVariables());
-    RETURN_IF_EXCEPTION(scope, encodedJSValue());
-    JSModuleRecord* moduleRecord = moduleAnalyzer.analyze(*moduleProgramNode);
+    if (UNLIKELY(scope.exception()))
+        return reject();
 
-    return JSValue::encode(moduleRecord);
+    return JSValue::encode(deferred->resolve(exec, moduleAnalyzer.analyze(*moduleProgramNode)));
 }
 
 EncodedJSValue JSC_HOST_CALL moduleLoaderPrototypeRequestedModules(ExecState* exec)
 {
     VM& vm = exec->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
-    JSModuleRecord* moduleRecord = jsDynamicCast<JSModuleRecord*>(vm, exec->argument(0));
+    auto* moduleRecord = jsDynamicCast<AbstractModuleRecord*>(vm, exec->argument(0));
     if (!moduleRecord) {
         scope.release();
         return JSValue::encode(constructEmptyArray(exec, nullptr));
@@ -157,14 +169,14 @@ EncodedJSValue JSC_HOST_CALL moduleLoaderPrototypeModuleDeclarationInstantiation
 {
     VM& vm = exec->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
-    JSModuleRecord* moduleRecord = jsDynamicCast<JSModuleRecord*>(vm, exec->argument(0));
+    auto* moduleRecord = jsDynamicCast<AbstractModuleRecord*>(vm, exec->argument(0));
     if (!moduleRecord)
         return JSValue::encode(jsUndefined());
 
     if (Options::dumpModuleLoadingState())
         dataLog("Loader [link] ", moduleRecord->moduleKey(), "\n");
 
-    moduleRecord->link(exec, exec->argument(1), exec->argument(2));
+    moduleRecord->link(exec, exec->argument(1));
     RETURN_IF_EXCEPTION(scope, encodedJSValue());
 
     return JSValue::encode(jsUndefined());
index bd06d3c9c25165ecdf0b7b842a20914d6ed59da7..c51286b7da960c73eaae1f2877fe62939347e4fe 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "JSArrayBuffer.h"
 #include "JSCJSValue.h"
+#include "JSSourceCode.h"
 #include "WebAssemblyFunction.h"
 #include "WebAssemblyWrapperFunction.h"
 
@@ -49,10 +50,16 @@ ALWAYS_INLINE uint32_t toNonWrappingUint32(ExecState* exec, JSValue value)
     return static_cast<uint32_t>(doubleValue);
 }
 
-ALWAYS_INLINE std::pair<uint8_t*, size_t> getWasmBufferFromValue(ExecState* exec, JSValue value)
+ALWAYS_INLINE std::pair<const uint8_t*, size_t> getWasmBufferFromValue(ExecState* exec, JSValue value)
 {
     VM& vm = exec->vm();
     auto throwScope = DECLARE_THROW_SCOPE(vm);
+
+    if (auto* source = jsDynamicCast<JSSourceCode*>(vm, value)) {
+        auto* provider = static_cast<WebAssemblySourceProvider*>(source->sourceCode().provider());
+        return { provider->data().data(), provider->data().size() };
+    }
+
     // If the given bytes argument is not a BufferSource, a TypeError exception is thrown.
     JSArrayBuffer* arrayBuffer = value.getObject() ? jsDynamicCast<JSArrayBuffer*>(vm, value.getObject()) : nullptr;
     JSArrayBufferView* arrayBufferView = value.getObject() ? jsDynamicCast<JSArrayBufferView*>(vm, value.getObject()) : nullptr;
@@ -76,7 +83,7 @@ ALWAYS_INLINE std::pair<uint8_t*, size_t> getWasmBufferFromValue(ExecState* exec
 ALWAYS_INLINE Vector<uint8_t> createSourceBufferFromValue(VM& vm, ExecState* exec, JSValue value)
 {
     auto throwScope = DECLARE_THROW_SCOPE(vm);
-    uint8_t* data;
+    const uint8_t* data;
     size_t byteSize;
     std::tie(data, byteSize) = getWasmBufferFromValue(exec, value);
     RETURN_IF_EXCEPTION(throwScope, Vector<uint8_t>());
index 771a640a32b8599a05a3df453637dd6b53a9c907..237998c69d94d153b113629b9fd8b74113b4b98c 100644 (file)
@@ -91,7 +91,7 @@ void JSWebAssemblyInstance::visitChildren(JSCell* cell, SlotVisitor& visitor)
         visitor.append(*thisObject->instance().importFunction<PoisonedBarrier<JSObject>>(i)); // This also keeps the functions' JSWebAssemblyInstance alive.
 }
 
-void JSWebAssemblyInstance::finalizeCreation(VM& vm, ExecState* exec, Ref<Wasm::CodeBlock>&& wasmCodeBlock)
+void JSWebAssemblyInstance::finalizeCreation(VM& vm, ExecState* exec, Ref<Wasm::CodeBlock>&& wasmCodeBlock, ModuleRunMode moduleRunMode)
 {
     m_instance->finalizeCreation(this, wasmCodeBlock.copyRef());
 
@@ -127,15 +127,24 @@ void JSWebAssemblyInstance::finalizeCreation(VM& vm, ExecState* exec, Ref<Wasm::
     }
 
     auto* moduleRecord = jsCast<WebAssemblyModuleRecord*>(m_moduleNamespaceObject->moduleRecord());
-    moduleRecord->link(exec, m_module.get(), this);
-    RETURN_IF_EXCEPTION(scope, void());
+    moduleRecord->prepareLink(vm, this);
 
-    JSValue startResult = moduleRecord->evaluate(exec);
-    UNUSED_PARAM(startResult);
-    RETURN_IF_EXCEPTION(scope, void());
+    if (moduleRunMode == ModuleRunMode::Run) {
+        moduleRecord->link(exec, jsNull());
+        RETURN_IF_EXCEPTION(scope, void());
+
+        JSValue startResult = moduleRecord->evaluate(exec);
+        UNUSED_PARAM(startResult);
+        RETURN_IF_EXCEPTION(scope, void());
+    }
+}
+
+Identifier JSWebAssemblyInstance::createPrivateModuleKey()
+{
+    return Identifier::fromUid(PrivateName(PrivateName::Description, "WebAssemblyInstance"));
 }
 
-JSWebAssemblyInstance* JSWebAssemblyInstance::create(VM& vm, ExecState* exec, JSWebAssemblyModule* jsModule, JSObject* importObject, Structure* instanceStructure, Ref<Wasm::Module>&& module)
+JSWebAssemblyInstance* JSWebAssemblyInstance::create(VM& vm, ExecState* exec, const Identifier& moduleKey, JSWebAssemblyModule* jsModule, JSObject* importObject, Structure* instanceStructure, Ref<Wasm::Module>&& module)
 {
     auto throwScope = DECLARE_THROW_SCOPE(vm);
     auto* globalObject = exec->lexicalGlobalObject();
@@ -158,7 +167,6 @@ JSWebAssemblyInstance* JSWebAssemblyInstance::create(VM& vm, ExecState* exec, JS
     if (moduleInformation.imports.size() && !importObject)
         return exception(createTypeError(exec, ASCIILiteral("can't make WebAssembly.Instance because there is no imports Object and the WebAssembly.Module requires imports")));
 
-    Identifier moduleKey = Identifier::fromUid(PrivateName(PrivateName::Description, "WebAssemblyInstance"));
     WebAssemblyModuleRecord* moduleRecord = WebAssemblyModuleRecord::create(exec, vm, globalObject->webAssemblyModuleRecordStructure(), moduleKey, moduleInformation);
     RETURN_IF_EXCEPTION(throwScope, nullptr);
 
index ed9b2b118bfd3a0b7ea9d2c4311e5ae19156fdf2..032b565f081e0e071bfcdb3abe79b99e78913f9b 100644 (file)
@@ -50,12 +50,15 @@ class JSWebAssemblyInstance final : public JSDestructibleObject {
 public:
     typedef JSDestructibleObject Base;
 
-    static JSWebAssemblyInstance* create(VM&, ExecState*, JSWebAssemblyModule*, JSObject* importObject, Structure*, Ref<Wasm::Module>&&);
+    static Identifier createPrivateModuleKey();
+
+    static JSWebAssemblyInstance* create(VM&, ExecState*, const Identifier& moduleKey, JSWebAssemblyModule*, JSObject* importObject, Structure*, Ref<Wasm::Module>&&);
     static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
 
     DECLARE_EXPORT_INFO;
 
-    void finalizeCreation(VM&, ExecState*, Ref<Wasm::CodeBlock>&&);
+    enum class ModuleRunMode { Run, None };
+    void finalizeCreation(VM&, ExecState*, Ref<Wasm::CodeBlock>&&, ModuleRunMode);
     
     Wasm::Instance& instance() { return m_instance.get(); }
     JSModuleNamespaceObject* moduleNamespaceObject() { return m_moduleNamespaceObject.get(); }
@@ -76,6 +79,8 @@ public:
         instance().setTable(makeRef(*table()->table()));
     }
 
+    JSWebAssemblyModule* module() const { return m_module.get(); }
+
     static size_t offsetOfPoisonedInstance() { return OBJECT_OFFSETOF(JSWebAssemblyInstance, m_instance); }
     static size_t offsetOfPoisonedCallee() { return OBJECT_OFFSETOF(JSWebAssemblyInstance, m_callee); }
 
@@ -89,8 +94,6 @@ protected:
     static void visitChildren(JSCell*, SlotVisitor&);
 
 private:
-    JSWebAssemblyModule* module() const { return m_module.get(); }
-
     PoisonedRef<JSWebAssemblyInstancePoison, Wasm::Instance> m_instance;
 
     PoisonedBarrier<JSWebAssemblyModule> m_module;
index b6788fa50c6454a20d35750d230f3ebac032c88c..49609893ae25fe8f1270fda61c56cc810030f117 100644 (file)
@@ -77,10 +77,10 @@ static EncodedJSValue JSC_HOST_CALL constructJSWebAssemblyInstance(ExecState* ex
     Structure* instanceStructure = InternalFunction::createSubclassStructure(exec, exec->newTarget(), exec->lexicalGlobalObject()->WebAssemblyInstanceStructure());
     RETURN_IF_EXCEPTION(scope, { });
 
-    JSWebAssemblyInstance* instance = JSWebAssemblyInstance::create(vm, exec, module, importObject, instanceStructure, Ref<Wasm::Module>(module->module()));
+    JSWebAssemblyInstance* instance = JSWebAssemblyInstance::create(vm, exec, JSWebAssemblyInstance::createPrivateModuleKey(), module, importObject, instanceStructure, Ref<Wasm::Module>(module->module()));
     RETURN_IF_EXCEPTION(scope, { });
 
-    instance->finalizeCreation(vm, exec, module->module().compileSync(&vm.wasmContext, instance->memoryMode(), &Wasm::createJSToWasmWrapper, &Wasm::wasmToJSException));
+    instance->finalizeCreation(vm, exec, module->module().compileSync(&vm.wasmContext, instance->memoryMode(), &Wasm::createJSToWasmWrapper, &Wasm::wasmToJSException), JSWebAssemblyInstance::ModuleRunMode::Run);
     RETURN_IF_EXCEPTION(scope, { });
     return JSValue::encode(instance);
 }
index e34646c6db81d86e67f82077af893a6ddf2cf36b..0e484758a4c1d610db2a88afd7c6c9f6ba53a41d 100644 (file)
@@ -86,14 +86,23 @@ void WebAssemblyModuleRecord::visitChildren(JSCell* cell, SlotVisitor& visitor)
     visitor.append(thisObject->m_startFunction);
 }
 
-void WebAssemblyModuleRecord::link(ExecState* exec, JSWebAssemblyModule* module, JSWebAssemblyInstance* instance)
+void WebAssemblyModuleRecord::prepareLink(VM& vm, JSWebAssemblyInstance* instance)
+{
+    RELEASE_ASSERT(!m_instance);
+    m_instance.set(vm, this, instance);
+}
+
+void WebAssemblyModuleRecord::link(ExecState* exec, JSValue)
 {
     VM& vm = exec->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
     UNUSED_PARAM(scope);
     auto* globalObject = exec->lexicalGlobalObject();
 
-    Wasm::CodeBlock* codeBlock = instance->instance().codeBlock();
+    RELEASE_ASSERT(m_instance);
+
+    Wasm::CodeBlock* codeBlock = m_instance->instance().codeBlock();
+    JSWebAssemblyModule* module = m_instance->module();
     const Wasm::ModuleInformation& moduleInformation = module->moduleInformation();
 
     SymbolTable* exportSymbolTable = module->exportSymbolTable();
@@ -110,12 +119,12 @@ void WebAssemblyModuleRecord::link(ExecState* exec, JSWebAssemblyModule* module,
             //   ii. (Note: At most one wrapper is created for any closure, so func is unique, even if there are multiple occurrances in the list. Moreover, if the item was an import that is already an Exported Function Exotic Object, then the original function object will be found. For imports that are regular JS functions, a new wrapper will be created.)
             if (exp.kindIndex < functionImportCount) {
                 unsigned functionIndex = exp.kindIndex;
-                JSObject* functionImport = instance->instance().importFunction<JSWebAssemblyInstance::PoisonedBarrier<JSObject>>(functionIndex)->get();
+                JSObject* functionImport = m_instance->instance().importFunction<JSWebAssemblyInstance::PoisonedBarrier<JSObject>>(functionIndex)->get();
                 if (isWebAssemblyHostFunction(vm, functionImport))
                     exportedValue = functionImport;
                 else {
                     Wasm::SignatureIndex signatureIndex = module->signatureIndexFromFunctionIndexSpace(functionIndex);
-                    exportedValue = WebAssemblyWrapperFunction::create(vm, globalObject, functionImport, functionIndex, instance, signatureIndex);
+                    exportedValue = WebAssemblyWrapperFunction::create(vm, globalObject, functionImport, functionIndex, m_instance.get(), signatureIndex);
                 }
             } else {
                 //   iii. Otherwise:
@@ -126,23 +135,23 @@ void WebAssemblyModuleRecord::link(ExecState* exec, JSWebAssemblyModule* module,
                 Wasm::WasmToWasmImportableFunction::LoadLocation entrypointLoadLocation = codeBlock->entrypointLoadLocationFromFunctionIndexSpace(exp.kindIndex);
                 Wasm::SignatureIndex signatureIndex = module->signatureIndexFromFunctionIndexSpace(exp.kindIndex);
                 const Wasm::Signature& signature = Wasm::SignatureInformation::get(signatureIndex);
-                WebAssemblyFunction* function = WebAssemblyFunction::create(vm, globalObject, signature.argumentCount(), String::fromUTF8(exp.field), instance, embedderEntrypointCallee, entrypointLoadLocation, signatureIndex);
+                WebAssemblyFunction* function = WebAssemblyFunction::create(vm, globalObject, signature.argumentCount(), String::fromUTF8(exp.field), m_instance.get(), embedderEntrypointCallee, entrypointLoadLocation, signatureIndex);
                 exportedValue = function;
             }
             break;
         }
         case Wasm::ExternalKind::Table: {
             // This should be guaranteed by module verification.
-            RELEASE_ASSERT(instance->table()); 
+            RELEASE_ASSERT(m_instance->table()); 
             ASSERT(exp.kindIndex == 0);
 
-            exportedValue = instance->table();
+            exportedValue = m_instance->table();
             break;
         }
         case Wasm::ExternalKind::Memory: {
             ASSERT(exp.kindIndex == 0);
 
-            exportedValue = instance->memory();
+            exportedValue = m_instance->memory();
             break;
         }
         case Wasm::ExternalKind::Global: {
@@ -152,7 +161,7 @@ void WebAssemblyModuleRecord::link(ExecState* exec, JSWebAssemblyModule* module,
             // Return ToJSValue(v).
             switch (global.type) {
             case Wasm::I32:
-                exportedValue = JSValue(instance->instance().loadI32Global(exp.kindIndex));
+                exportedValue = JSValue(m_instance->instance().loadI32Global(exp.kindIndex));
                 break;
 
             case Wasm::I64:
@@ -160,11 +169,11 @@ void WebAssemblyModuleRecord::link(ExecState* exec, JSWebAssemblyModule* module,
                 return;
 
             case Wasm::F32:
-                exportedValue = JSValue(instance->instance().loadF32Global(exp.kindIndex));
+                exportedValue = JSValue(m_instance->instance().loadF32Global(exp.kindIndex));
                 break;
 
             case Wasm::F64:
-                exportedValue = JSValue(instance->instance().loadF64Global(exp.kindIndex));
+                exportedValue = JSValue(m_instance->instance().loadF64Global(exp.kindIndex));
                 break;
 
             default:
@@ -191,18 +200,15 @@ void WebAssemblyModuleRecord::link(ExecState* exec, JSWebAssemblyModule* module,
         ASSERT(!signature.argumentCount());
         ASSERT(signature.returnType() == Wasm::Void);
         if (startFunctionIndexSpace < codeBlock->functionImportCount()) {
-            JSObject* startFunction = instance->instance().importFunction<JSWebAssemblyInstance::PoisonedBarrier<JSObject>>(startFunctionIndexSpace)->get();
+            JSObject* startFunction = m_instance->instance().importFunction<JSWebAssemblyInstance::PoisonedBarrier<JSObject>>(startFunctionIndexSpace)->get();
             m_startFunction.set(vm, this, startFunction);
         } else {
             Wasm::Callee& embedderEntrypointCallee = codeBlock->embedderEntrypointCalleeFromFunctionIndexSpace(startFunctionIndexSpace);
             Wasm::WasmToWasmImportableFunction::LoadLocation entrypointLoadLocation = codeBlock->entrypointLoadLocationFromFunctionIndexSpace(startFunctionIndexSpace);
-            WebAssemblyFunction* function = WebAssemblyFunction::create(vm, globalObject, signature.argumentCount(), "start", instance, embedderEntrypointCallee, entrypointLoadLocation, signatureIndex);
+            WebAssemblyFunction* function = WebAssemblyFunction::create(vm, globalObject, signature.argumentCount(), "start", m_instance.get(), embedderEntrypointCallee, entrypointLoadLocation, signatureIndex);
             m_startFunction.set(vm, this, function);
         }
     }
-
-    RELEASE_ASSERT(!m_instance);
-    m_instance.set(vm, this, instance);
     m_moduleEnvironment.set(vm, this, moduleEnvironment);
 }
 
index fce1d6463903572060c9d997c10cebf0dacdd9d8..417a0c60837d45ceb5631f4b0f475db3b5fb389a 100644 (file)
@@ -48,7 +48,8 @@ public:
     static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
     static WebAssemblyModuleRecord* create(ExecState*, VM&, Structure*, const Identifier&, const Wasm::ModuleInformation&);
 
-    void link(ExecState*, JSWebAssemblyModule*, JSWebAssemblyInstance*);
+    void prepareLink(VM&, JSWebAssemblyInstance*);
+    void link(ExecState*, JSValue scriptFetcher);
     JS_EXPORT_PRIVATE JSValue evaluate(ExecState*);
 
 private:
index 46441d3d22f6a6b2a0ddf599aec54f63f2d4b26d..4ef647a3baa4cce53ebc944373b7ec9e0a3689a6 100644 (file)
@@ -32,6 +32,7 @@
 #include "Exception.h"
 #include "FunctionPrototype.h"
 #include "JSCInlines.h"
+#include "JSModuleNamespaceObject.h"
 #include "JSPromiseDeferred.h"
 #include "JSToWasm.h"
 #include "JSWebAssemblyHelpers.h"
@@ -120,16 +121,21 @@ static EncodedJSValue JSC_HOST_CALL webAssemblyCompileFunc(ExecState* exec)
     }
 }
 
-enum class Resolve { WithInstance, WithModuleAndInstance };
-static void resolve(VM& vm, ExecState* exec, JSPromiseDeferred* promise, JSWebAssemblyInstance* instance, JSWebAssemblyModule* module, Ref<Wasm::CodeBlock>&& codeBlock, Resolve resolveKind)
+enum class Resolve { WithInstance, WithModuleRecord, WithModuleAndInstance };
+static void resolve(VM& vm, ExecState* exec, JSPromiseDeferred* promise, JSWebAssemblyInstance* instance, JSWebAssemblyModule* module, Ref<Wasm::CodeBlock>&& codeBlock, Resolve resolveKind, JSWebAssemblyInstance::ModuleRunMode moduleRunMode)
 {
     auto scope = DECLARE_CATCH_SCOPE(vm);
-    instance->finalizeCreation(vm, exec, WTFMove(codeBlock));
+    instance->finalizeCreation(vm, exec, WTFMove(codeBlock), moduleRunMode);
     RETURN_IF_EXCEPTION(scope, reject(exec, scope, promise));
 
     if (resolveKind == Resolve::WithInstance)
         promise->resolve(exec, instance);
-    else {
+    else if (resolveKind == Resolve::WithModuleRecord) {
+        auto* moduleRecord = instance->moduleNamespaceObject()->moduleRecord();
+        if (Options::dumpModuleRecord())
+            moduleRecord->dump();
+        promise->resolve(exec, moduleRecord);
+    } else {
         JSObject* result = constructEmptyObject(exec);
         result->putDirect(vm, Identifier::fromString(&vm, ASCIILiteral("module")), module);
         result->putDirect(vm, Identifier::fromString(&vm, ASCIILiteral("instance")), instance);
@@ -138,11 +144,11 @@ static void resolve(VM& vm, ExecState* exec, JSPromiseDeferred* promise, JSWebAs
     CLEAR_AND_RETURN_IF_EXCEPTION(scope, void());
 }
 
-static void instantiate(VM& vm, ExecState* exec, JSPromiseDeferred* promise, JSWebAssemblyModule* module, JSObject* importObject, Resolve resolveKind)
+static void instantiate(VM& vm, ExecState* exec, JSPromiseDeferred* promise, JSWebAssemblyModule* module, JSObject* importObject, const Identifier& moduleKey, Resolve resolveKind, JSWebAssemblyInstance::ModuleRunMode moduleRunMode)
 {
     auto scope = DECLARE_CATCH_SCOPE(vm);
     // In order to avoid potentially recompiling a module. We first gather all the import/memory information prior to compiling code.
-    JSWebAssemblyInstance* instance = JSWebAssemblyInstance::create(vm, exec, module, importObject, exec->lexicalGlobalObject()->WebAssemblyInstanceStructure(), Ref<Wasm::Module>(module->module()));
+    JSWebAssemblyInstance* instance = JSWebAssemblyInstance::create(vm, exec, moduleKey, module, importObject, exec->lexicalGlobalObject()->WebAssemblyInstanceStructure(), Ref<Wasm::Module>(module->module()));
     RETURN_IF_EXCEPTION(scope, reject(exec, scope, promise));
 
     Vector<Strong<JSCell>> dependencies;
@@ -150,41 +156,54 @@ static void instantiate(VM& vm, ExecState* exec, JSPromiseDeferred* promise, JSW
     dependencies.append(Strong<JSCell>(vm, instance));
     vm.promiseDeferredTimer->addPendingPromise(promise, WTFMove(dependencies));
     // Note: This completion task may or may not get called immediately.
-    module->module().compileAsync(&vm.wasmContext, instance->memoryMode(), createSharedTask<Wasm::CodeBlock::CallbackType>([promise, instance, module, resolveKind, &vm] (Ref<Wasm::CodeBlock>&& refCodeBlock) mutable {
+    module->module().compileAsync(&vm.wasmContext, instance->memoryMode(), createSharedTask<Wasm::CodeBlock::CallbackType>([promise, instance, module, resolveKind, moduleRunMode, &vm] (Ref<Wasm::CodeBlock>&& refCodeBlock) mutable {
         RefPtr<Wasm::CodeBlock> codeBlock = WTFMove(refCodeBlock);
-        vm.promiseDeferredTimer->scheduleWorkSoon(promise, [promise, instance, module, resolveKind, &vm, codeBlock = WTFMove(codeBlock)] () mutable {
+        vm.promiseDeferredTimer->scheduleWorkSoon(promise, [promise, instance, module, resolveKind, moduleRunMode, &vm, codeBlock = WTFMove(codeBlock)] () mutable {
             ExecState* exec = instance->globalObject()->globalExec();
-            resolve(vm, exec, promise, instance, module, codeBlock.releaseNonNull(), resolveKind);
+            resolve(vm, exec, promise, instance, module, codeBlock.releaseNonNull(), resolveKind, moduleRunMode);
         });
     }), &Wasm::createJSToWasmWrapper, &Wasm::wasmToJSException);
 }
 
-static void compileAndInstantiate(VM& vm, ExecState* exec, JSPromiseDeferred* promise, JSValue buffer, JSObject* importObject)
+static void compileAndInstantiate(VM& vm, ExecState* exec, JSPromiseDeferred* promise, const Identifier& moduleKey, JSValue buffer, JSObject* importObject, Resolve resolveKind, JSWebAssemblyInstance::ModuleRunMode moduleRunMode)
 {
     auto scope = DECLARE_CATCH_SCOPE(vm);
 
     auto* globalObject = exec->lexicalGlobalObject();
 
+    JSCell* moduleKeyCell = identifierToJSValue(vm, moduleKey).asCell();
     Vector<Strong<JSCell>> dependencies;
     dependencies.append(Strong<JSCell>(vm, importObject));
+    dependencies.append(Strong<JSCell>(vm, moduleKeyCell));
     vm.promiseDeferredTimer->addPendingPromise(promise, WTFMove(dependencies));
 
     Vector<uint8_t> source = createSourceBufferFromValue(vm, exec, buffer);
     RETURN_IF_EXCEPTION(scope, reject(exec, scope, promise));
 
-    Wasm::Module::validateAsync(&vm.wasmContext, WTFMove(source), createSharedTask<Wasm::Module::CallbackType>([promise, importObject, globalObject, &vm] (Wasm::Module::ValidationResult&& result) mutable {
-        vm.promiseDeferredTimer->scheduleWorkSoon(promise, [promise, importObject, globalObject, result = WTFMove(result), &vm] () mutable {
+    Wasm::Module::validateAsync(&vm.wasmContext, WTFMove(source), createSharedTask<Wasm::Module::CallbackType>([promise, importObject, moduleKeyCell, globalObject, resolveKind, moduleRunMode, &vm] (Wasm::Module::ValidationResult&& result) mutable {
+        vm.promiseDeferredTimer->scheduleWorkSoon(promise, [promise, importObject, moduleKeyCell, globalObject, result = WTFMove(result), resolveKind, moduleRunMode, &vm] () mutable {
             auto scope = DECLARE_CATCH_SCOPE(vm);
             ExecState* exec = globalObject->globalExec();
             JSWebAssemblyModule* module = JSWebAssemblyModule::createStub(vm, exec, globalObject->WebAssemblyModuleStructure(), WTFMove(result));
             if (UNLIKELY(scope.exception()))
                 return reject(exec, scope, promise);
 
-            instantiate(vm, exec, promise, module, importObject, Resolve::WithModuleAndInstance);
+            const Identifier moduleKey = JSValue(moduleKeyCell).toPropertyKey(exec);
+            if (UNLIKELY(scope.exception()))
+                return reject(exec, scope, promise);
+
+            instantiate(vm, exec, promise, module, importObject, moduleKey, resolveKind, moduleRunMode);
         });
     }));
 }
 
+JSValue WebAssemblyPrototype::instantiate(ExecState* exec, JSPromiseDeferred* promise, const Identifier& moduleKey, JSValue argument)
+{
+    VM& vm = exec->vm();
+    compileAndInstantiate(vm, exec, promise, moduleKey, argument, nullptr, Resolve::WithModuleRecord, JSWebAssemblyInstance::ModuleRunMode::None);
+    return promise->promise();
+}
+
 static EncodedJSValue JSC_HOST_CALL webAssemblyInstantiateFunc(ExecState* exec)
 {
     VM& vm = exec->vm();
@@ -206,9 +225,9 @@ static EncodedJSValue JSC_HOST_CALL webAssemblyInstantiateFunc(ExecState* exec)
         } else {
             JSValue firstArgument = exec->argument(0);
             if (auto* module = jsDynamicCast<JSWebAssemblyModule*>(vm, firstArgument))
-                instantiate(vm, exec, promise, module, importObject, Resolve::WithInstance);
+                instantiate(vm, exec, promise, module, importObject, JSWebAssemblyInstance::createPrivateModuleKey(), Resolve::WithInstance, JSWebAssemblyInstance::ModuleRunMode::Run);
             else
-                compileAndInstantiate(vm, exec, promise, firstArgument, importObject);
+                compileAndInstantiate(vm, exec, promise, JSWebAssemblyInstance::createPrivateModuleKey(), firstArgument, importObject, Resolve::WithModuleAndInstance, JSWebAssemblyInstance::ModuleRunMode::Run);
         }
 
         return JSValue::encode(promise->promise());
@@ -220,7 +239,7 @@ static EncodedJSValue JSC_HOST_CALL webAssemblyValidateFunc(ExecState* exec)
     VM& vm = exec->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
 
-    uint8_t* base;
+    const uint8_t* base;
     size_t byteSize;
     std::tie(base, byteSize) = getWasmBufferFromValue(exec, exec->argument(0));
     RETURN_IF_EXCEPTION(scope, encodedJSValue());
index d5d0d6cbdef7b2c9f25795e5a0db5ba05dc42dcc..bbb226dbcc699e3f0f0b8af1c95470559c6954a1 100644 (file)
@@ -42,6 +42,8 @@ public:
 
     DECLARE_INFO;
 
+    static JSValue instantiate(ExecState*, JSPromiseDeferred*, const Identifier&, JSValue);
+
 protected:
     void finishCreation(VM&);