[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 a3a2643..ea71c1b 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 f2124ef..87c8802 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 4f1d38a..ad0ced6 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 93f2225..eef91eb 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 40c7edc..10a44af 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 2e68e82..0d0c2fc 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 33253df..2c8042d 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 592995b..5588b2f 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 1be3c7a..908591d 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 6fa2f72..a7c99dc 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 cdfcc40..ac2dcfa 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 3d4f44a..4e093e1 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 bd06d3c..c51286b 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 771a640..237998c 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 ed9b2b1..032b565 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 b6788fa..4960989 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 e34646c..0e48475 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 fce1d64..417a0c6 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 46441d3..4ef647a 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 d5d0d6c..bbb226d 100644 (file)
@@ -42,6 +42,8 @@ public:
 
     DECLARE_INFO;
 
+    static JSValue instantiate(ExecState*, JSPromiseDeferred*, const Identifier&, JSValue);
+
 protected:
     void finishCreation(VM&);