⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 284702 in webkit


Ignore:
Timestamp:
Oct 22, 2021, 11:35:42 AM (5 years ago)
Author:
commit-queue@webkit.org
Message:

Change WebAssembly module import linking time to evaluate step.
https://bugs.webkit.org/show_bug.cgi?id=231114

Patch by Asumu Takikawa <asumu@igalia.com> on 2021-10-22
Reviewed by Yusuke Suzuki.

JSTests:

Added test cases based on Wasm/ESM proposal examples from:

https://github.com/WebAssembly/esm-integration/blob/main/proposals/esm-integration/EXAMPLES.md

The new tests cases cover the bindings made for both JS<->Wasm
and Wasm<->JS cyclic module cases, and importing values from JS
into Wasm modules. The tests do not cover importing memory values
as this does not work yet.

  • wasm/modules/wasm-js-cycle.js:
  • wasm/modules/wasm-js-cycle/entry-global.wasm:
  • wasm/modules/wasm-js-cycle/entry-global.wat:
  • wasm/modules/wasm-js-cycle/entry-table.wasm:
  • wasm/modules/wasm-js-cycle/entry-table.wat:
  • wasm/modules/wasm-js-cycle/global.js:

(from.string_appeared_here.export.incrementGlobal): Deleted.

  • wasm/modules/wasm-js-cycle/table.js:

(from.string_appeared_here.export.setTable): Deleted.

  • wasm/modules/js-wasm-cycle.js:

(then):

  • wasm/modules/js-wasm-cycle/entry-function.js: Added.

(f):

  • wasm/modules/js-wasm-cycle/entry-i32-global.js: Added.
  • wasm/modules/js-wasm-cycle/entry-i32-value.js: Added.
  • wasm/modules/js-wasm-cycle/entry-memory.js: Added.
  • wasm/modules/js-wasm-cycle/entry-table.js: Added.
  • wasm/modules/js-wasm-cycle/entry-wasm-global.js: Added.

(f):

  • wasm/modules/js-wasm-cycle/entry-wasm-memory.js: Added.

(f):

  • wasm/modules/js-wasm-cycle/entry-wasm-table.js: Added.

(f):

  • wasm/modules/js-wasm-cycle/function.wasm: Added.
  • wasm/modules/js-wasm-cycle/function.wat: Added.
  • wasm/modules/js-wasm-cycle/i32-global.wasm: Added.
  • wasm/modules/js-wasm-cycle/i32-global.wat: Added.
  • wasm/modules/js-wasm-cycle/i32-value.wasm: Added.
  • wasm/modules/js-wasm-cycle/i32-value.wat: Added.
  • wasm/modules/js-wasm-cycle/memory.wasm: Added.
  • wasm/modules/js-wasm-cycle/memory.wat: Added.
  • wasm/modules/js-wasm-cycle/table.wasm: Added.
  • wasm/modules/js-wasm-cycle/table.wat: Added.
  • wasm/modules/js-wasm-cycle/wasm-global.wasm: Added.
  • wasm/modules/js-wasm-cycle/wasm-global.wat: Added.
  • wasm/modules/js-wasm-cycle/wasm-memory.wasm: Added.
  • wasm/modules/js-wasm-cycle/wasm-memory.wat: Added.
  • wasm/modules/js-wasm-cycle/wasm-table.wasm: Added.
  • wasm/modules/js-wasm-cycle/wasm-table.wat: Added.
  • wasm/modules/wasm-imports-js-exports.js:
  • wasm/modules/wasm-imports-js-exports/global.js: Added.
  • wasm/modules/wasm-imports-js-exports/global.wasm: Added.
  • wasm/modules/wasm-imports-js-exports/global.wat: Added.
  • wasm/modules/wasm-imports-js-exports/table.js: Added.
  • wasm/modules/wasm-imports-js-exports/table.wasm: Added.
  • wasm/modules/wasm-imports-js-exports/table.wat: Added.
  • wasm/modules/wasm-js-cycle.js:
  • wasm/modules/wasm-js-cycle/entry-global.wasm: Added.
  • wasm/modules/wasm-js-cycle/entry-global.wat: Added.
  • wasm/modules/wasm-js-cycle/entry-memory.wasm: Added.
  • wasm/modules/wasm-js-cycle/entry-memory.wat: Added.
  • wasm/modules/wasm-js-cycle/entry-table.wasm: Added.
  • wasm/modules/wasm-js-cycle/entry-table.wat: Added.
  • wasm/modules/wasm-js-cycle/global.js: Added.

(export.incrementGlobal):

  • wasm/modules/wasm-js-cycle/memory.js: Added.

(from.string_appeared_here.export.setMemory):

  • wasm/modules/wasm-js-cycle/table.js: Added.

(export.setTable):

Source/JavaScriptCore:

Moves the Wasm module import linking code to execute in the
module evaluation step, which is the behavior specified in the
Wasm/ESM-integration proposal:

https://github.com/WebAssembly/esm-integration/tree/main/proposals/esm-integration#evaluate

  • runtime/AbstractModuleRecord.cpp:

(JSC::AbstractModuleRecord::link):
(JSC::AbstractModuleRecord::evaluate):

  • wasm/js/JSWebAssemblyInstance.cpp:

(JSC::JSWebAssemblyInstance::finalizeCreation):

  • wasm/js/WebAssemblyModuleRecord.cpp:

(JSC::WebAssemblyModuleRecord::link):
(JSC::WebAssemblyModuleRecord::initializeImportsAndExports):
(JSC::WebAssemblyModuleRecord::linkImpl): Deleted.

  • wasm/js/WebAssemblyModuleRecord.h:
Location:
trunk
Files:
39 added
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r284635 r284702  
     12021-10-22  Asumu Takikawa  <asumu@igalia.com>
     2
     3        Change WebAssembly module import linking time to evaluate step.
     4        https://bugs.webkit.org/show_bug.cgi?id=231114
     5
     6        Reviewed by Yusuke Suzuki.
     7
     8        Added test cases based on Wasm/ESM proposal examples from:
     9
     10          https://github.com/WebAssembly/esm-integration/blob/main/proposals/esm-integration/EXAMPLES.md
     11
     12        The new tests cases cover the bindings made for both JS<->Wasm
     13        and Wasm<->JS cyclic module cases, and importing values from JS
     14        into Wasm modules. The tests do not cover importing memory values
     15        as this does not work yet.
     16
     17        * wasm/modules/wasm-js-cycle.js:
     18        * wasm/modules/wasm-js-cycle/entry-global.wasm:
     19        * wasm/modules/wasm-js-cycle/entry-global.wat:
     20        * wasm/modules/wasm-js-cycle/entry-table.wasm:
     21        * wasm/modules/wasm-js-cycle/entry-table.wat:
     22        * wasm/modules/wasm-js-cycle/global.js:
     23        (from.string_appeared_here.export.incrementGlobal): Deleted.
     24        * wasm/modules/wasm-js-cycle/table.js:
     25        (from.string_appeared_here.export.setTable): Deleted.
     26
     27        * wasm/modules/js-wasm-cycle.js:
     28        (then):
     29        * wasm/modules/js-wasm-cycle/entry-function.js: Added.
     30        (f):
     31        * wasm/modules/js-wasm-cycle/entry-i32-global.js: Added.
     32        * wasm/modules/js-wasm-cycle/entry-i32-value.js: Added.
     33        * wasm/modules/js-wasm-cycle/entry-memory.js: Added.
     34        * wasm/modules/js-wasm-cycle/entry-table.js: Added.
     35        * wasm/modules/js-wasm-cycle/entry-wasm-global.js: Added.
     36        (f):
     37        * wasm/modules/js-wasm-cycle/entry-wasm-memory.js: Added.
     38        (f):
     39        * wasm/modules/js-wasm-cycle/entry-wasm-table.js: Added.
     40        (f):
     41        * wasm/modules/js-wasm-cycle/function.wasm: Added.
     42        * wasm/modules/js-wasm-cycle/function.wat: Added.
     43        * wasm/modules/js-wasm-cycle/i32-global.wasm: Added.
     44        * wasm/modules/js-wasm-cycle/i32-global.wat: Added.
     45        * wasm/modules/js-wasm-cycle/i32-value.wasm: Added.
     46        * wasm/modules/js-wasm-cycle/i32-value.wat: Added.
     47        * wasm/modules/js-wasm-cycle/memory.wasm: Added.
     48        * wasm/modules/js-wasm-cycle/memory.wat: Added.
     49        * wasm/modules/js-wasm-cycle/table.wasm: Added.
     50        * wasm/modules/js-wasm-cycle/table.wat: Added.
     51        * wasm/modules/js-wasm-cycle/wasm-global.wasm: Added.
     52        * wasm/modules/js-wasm-cycle/wasm-global.wat: Added.
     53        * wasm/modules/js-wasm-cycle/wasm-memory.wasm: Added.
     54        * wasm/modules/js-wasm-cycle/wasm-memory.wat: Added.
     55        * wasm/modules/js-wasm-cycle/wasm-table.wasm: Added.
     56        * wasm/modules/js-wasm-cycle/wasm-table.wat: Added.
     57        * wasm/modules/wasm-imports-js-exports.js:
     58        * wasm/modules/wasm-imports-js-exports/global.js: Added.
     59        * wasm/modules/wasm-imports-js-exports/global.wasm: Added.
     60        * wasm/modules/wasm-imports-js-exports/global.wat: Added.
     61        * wasm/modules/wasm-imports-js-exports/table.js: Added.
     62        * wasm/modules/wasm-imports-js-exports/table.wasm: Added.
     63        * wasm/modules/wasm-imports-js-exports/table.wat: Added.
     64        * wasm/modules/wasm-js-cycle.js:
     65        * wasm/modules/wasm-js-cycle/entry-global.wasm: Added.
     66        * wasm/modules/wasm-js-cycle/entry-global.wat: Added.
     67        * wasm/modules/wasm-js-cycle/entry-memory.wasm: Added.
     68        * wasm/modules/wasm-js-cycle/entry-memory.wat: Added.
     69        * wasm/modules/wasm-js-cycle/entry-table.wasm: Added.
     70        * wasm/modules/wasm-js-cycle/entry-table.wat: Added.
     71        * wasm/modules/wasm-js-cycle/global.js: Added.
     72        (export.incrementGlobal):
     73        * wasm/modules/wasm-js-cycle/memory.js: Added.
     74        (from.string_appeared_here.export.setMemory):
     75        * wasm/modules/wasm-js-cycle/table.js: Added.
     76        (export.setTable):
     77
    1782021-10-21  Yusuke Suzuki  <ysuzuki@apple.com>
    279
  • trunk/JSTests/wasm/modules/js-wasm-cycle.js

    r260690 r284702  
    11import * as assert from '../assert.js';
    2 import("./js-wasm-cycle/entry.js").then($vm.abort, function (error) {
    3     assert.eq(String(error), `LinkError: import function ./entry.js:return42 must be callable`);
     2import { return42 } from "./js-wasm-cycle/entry.js";
     3
     4assert.eq(return42(), 42);
     5
     6// Test the state of bindings with JS<->Wasm module cycles.
     7// https://github.com/WebAssembly/esm-integration/blob/main/proposals/esm-integration/EXAMPLES.md#js---wasm-cycle-where-js-is-higher-in-the-module-graph
     8
     9// Testing JS exports.
     10import("./js-wasm-cycle/entry-i32-global.js").then($vm.abort, function (error) {
     11    assert.eq(String(error), `LinkError: imported global ./entry-i32-global.js:glob must be a number`);
    412}).then(function () { }, $vm.abort);
     13
     14import("./js-wasm-cycle/entry-i32-value.js").then($vm.abort, function (error) {
     15    assert.eq(String(error), `LinkError: imported global ./entry-i32-value.js:glob must be a number`);
     16}).then(function () { }, $vm.abort);
     17
     18import("./js-wasm-cycle/entry-table.js").then($vm.abort, function (error) {
     19    assert.eq(String(error), `LinkError: Table import ./entry-table.js:t is not an instance of WebAssembly.Table`);
     20}).then(function () { }, $vm.abort);
     21
     22import("./js-wasm-cycle/entry-memory.js").then($vm.abort, function (error) {
     23    assert.eq(String(error), `LinkError: Memory import ./entry-memory.js:m is not an instance of WebAssembly.Memory`);
     24}).then(function () { }, $vm.abort);
     25
     26// Test Wasm exports.
     27import { g } from "./js-wasm-cycle/entry-wasm-global.js";
     28assert.instanceof(g, WebAssembly.Global);
     29assert.eq(g.valueOf(), 42);
     30
     31import { m } from "./js-wasm-cycle/entry-wasm-memory.js";
     32assert.instanceof(m, WebAssembly.Memory);
     33
     34import { t } from "./js-wasm-cycle/entry-wasm-table.js";
     35assert.instanceof(t, WebAssembly.Table);
     36
     37// This case tests both Wasm and JS export.
     38import { f2 } from "./js-wasm-cycle/entry-function.js";
     39assert.isFunction(f2);
     40assert.eq(f2(), 43);
  • trunk/JSTests/wasm/modules/wasm-imports-js-exports.js

    r230759 r284702  
    66assert.eq(addOne(-2), -1);
    77assert.eq(addOne(0x7fffffff), -2147483648);
     8
     9import { incrementCount } from "./wasm-imports-js-exports/global.wasm";
     10import { count } from "./wasm-imports-js-exports/global.js";
     11
     12assert.isFunction(incrementCount);
     13assert.eq(count.valueOf(), 42);
     14incrementCount();
     15assert.eq(count.valueOf(), 43);
     16
     17import { getElem } from "./wasm-imports-js-exports/table.wasm";
     18
     19assert.isFunction(getElem);
     20assert.eq(getElem(), "foo");
  • trunk/JSTests/wasm/modules/wasm-js-cycle.js

    r230759 r284702  
    33
    44assert.eq(return42(), 42);
     5
     6import { getFromJSGlobal, g } from "./wasm-js-cycle/entry-global.wasm"
     7import { globalFromJS, incrementGlobal } from "./wasm-js-cycle/global.js"
     8
     9assert.instanceof(g, WebAssembly.Global);
     10assert.eq(g.valueOf(), 42);
     11incrementGlobal();
     12assert.eq(g.valueOf(), 43);
     13
     14assert.isFunction(getFromJSGlobal);
     15assert.eq(getFromJSGlobal(), globalFromJS.valueOf());
     16globalFromJS.value = 84;
     17assert.eq(getFromJSGlobal(), globalFromJS.valueOf());
     18
     19import { getFromJSTable, t } from "./wasm-js-cycle/entry-table.wasm"
     20import { tableFromJS, setTable } from "./wasm-js-cycle/table.js"
     21
     22assert.instanceof(t, WebAssembly.Table);
     23assert.eq(t.get(0), null);
     24setTable(0, "foo");
     25assert.eq(t.get(0), "foo");
     26
     27assert.isFunction(getFromJSTable);
     28assert.eq(getFromJSTable(), tableFromJS.get(0));
     29tableFromJS.set(0, "foo");
     30assert.eq(getFromJSTable(), tableFromJS.get(0));
     31
     32import { m } from "./wasm-js-cycle/entry-memory.wasm"
     33import { setMemory } from "./wasm-js-cycle/memory.js"
     34
     35assert.instanceof(m, WebAssembly.Memory);
     36const view = new Int32Array(m.buffer);
     37assert.eq(view[0], 0);
     38setMemory(0, 42);
     39assert.eq(view[0], 42);
  • trunk/Source/JavaScriptCore/ChangeLog

    r284700 r284702  
     12021-10-22  Asumu Takikawa  <asumu@igalia.com>
     2
     3        Change WebAssembly module import linking time to evaluate step.
     4        https://bugs.webkit.org/show_bug.cgi?id=231114
     5
     6        Reviewed by Yusuke Suzuki.
     7
     8        Moves the Wasm module import linking code to execute in the
     9        module evaluation step, which is the behavior specified in the
     10        Wasm/ESM-integration proposal:
     11
     12          https://github.com/WebAssembly/esm-integration/tree/main/proposals/esm-integration#evaluate
     13
     14        * runtime/AbstractModuleRecord.cpp:
     15        (JSC::AbstractModuleRecord::link):
     16        (JSC::AbstractModuleRecord::evaluate):
     17        * wasm/js/JSWebAssemblyInstance.cpp:
     18        (JSC::JSWebAssemblyInstance::finalizeCreation):
     19        * wasm/js/WebAssemblyModuleRecord.cpp:
     20        (JSC::WebAssemblyModuleRecord::link):
     21        (JSC::WebAssemblyModuleRecord::initializeImportsAndExports):
     22        (JSC::WebAssemblyModuleRecord::linkImpl): Deleted.
     23        * wasm/js/WebAssemblyModuleRecord.h:
     24
    1252021-10-22  Mikhail R. Gadelha  <mikhail@igalia.com>
    226
  • trunk/Source/JavaScriptCore/runtime/AbstractModuleRecord.cpp

    r279924 r284702  
    823823        return jsModuleRecord->link(globalObject, scriptFetcher);
    824824#if ENABLE(WEBASSEMBLY)
     825    // WebAssembly module imports and exports are set up in the module record's
     826    // evaluate() step. At this point, imports are just initialized as TDZ.
    825827    if (auto* wasmModuleRecord = jsDynamicCast<WebAssemblyModuleRecord*>(vm, this))
    826         return wasmModuleRecord->link(globalObject, scriptFetcher, nullptr, Wasm::CreationMode::FromModuleLoader);
     828        return wasmModuleRecord->link(globalObject, scriptFetcher);
    827829#endif
    828830    RELEASE_ASSERT_NOT_REACHED();
     
    833835{
    834836    VM& vm = globalObject->vm();
     837    auto scope = DECLARE_THROW_SCOPE(vm);
     838
    835839    if (auto* jsModuleRecord = jsDynamicCast<JSModuleRecord*>(vm, this))
    836         return jsModuleRecord->evaluate(globalObject, sentValue, resumeMode);
     840        RELEASE_AND_RETURN(scope, jsModuleRecord->evaluate(globalObject, sentValue, resumeMode));
    837841#if ENABLE(WEBASSEMBLY)
    838     if (auto* wasmModuleRecord = jsDynamicCast<WebAssemblyModuleRecord*>(vm, this))
    839         return wasmModuleRecord->evaluate(globalObject);
     842    if (auto* wasmModuleRecord = jsDynamicCast<WebAssemblyModuleRecord*>(vm, this)) {
     843        // WebAssembly imports need to be supplied during evaluation so that, e.g.,
     844        // JS module exports are actually available to be read and installed as import
     845        // bindings.
     846        wasmModuleRecord->initializeImportsAndExports(globalObject, nullptr, Wasm::CreationMode::FromModuleLoader);
     847        RETURN_IF_EXCEPTION(scope, jsUndefined());
     848        RELEASE_AND_RETURN(scope, wasmModuleRecord->evaluate(globalObject));
     849    }
    840850#endif
    841851    RELEASE_ASSERT_NOT_REACHED();
  • trunk/Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.cpp

    r283852 r284702  
    144144
    145145    if (creationMode == Wasm::CreationMode::FromJS) {
    146         m_moduleRecord->link(globalObject, jsNull(), importObject, creationMode);
     146        m_moduleRecord->link(globalObject, jsNull());
     147        RETURN_IF_EXCEPTION(scope, void());
     148        m_moduleRecord->initializeImportsAndExports(globalObject, importObject, creationMode);
    147149        RETURN_IF_EXCEPTION(scope, void());
    148150
  • trunk/Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp

    r283852 r284702  
    9999}
    100100
    101 Synchronousness WebAssemblyModuleRecord::link(JSGlobalObject* globalObject, JSValue, JSObject* importObject, Wasm::CreationMode creationMode)
    102 {
    103     linkImpl(globalObject, importObject, creationMode);
     101Synchronousness WebAssemblyModuleRecord::link(JSGlobalObject* globalObject, JSValue)
     102{
     103    VM& vm = globalObject->vm();
     104
     105    RELEASE_ASSERT(m_instance);
     106
     107    JSWebAssemblyModule* module = m_instance->module();
     108    SymbolTable* exportSymbolTable = module->exportSymbolTable();
     109
     110    JSModuleEnvironment* moduleEnvironment = JSModuleEnvironment::create(vm, globalObject, nullptr, exportSymbolTable, jsTDZValue(), this);
     111    setModuleEnvironment(globalObject, moduleEnvironment);
     112
    104113    return Synchronousness::Sync;
    105114}
    106115
    107 void WebAssemblyModuleRecord::linkImpl(JSGlobalObject* globalObject, JSObject* importObject, Wasm::CreationMode creationMode)
     116void WebAssemblyModuleRecord::initializeImportsAndExports(JSGlobalObject* globalObject, JSObject* importObject, Wasm::CreationMode creationMode)
    108117{
    109118    VM& vm = globalObject->vm();
     
    516525    }
    517526
    518     SymbolTable* exportSymbolTable = module->exportSymbolTable();
    519 
    520527    // Let exports be a list of (string, JS value) pairs that is mapped from each external value e in instance.exports as follows:
    521528    // https://webassembly.github.io/spec/js-api/index.html#create-an-exports-object
    522529    JSObject* exportsObject = constructEmptyObject(vm, globalObject->nullPrototypeObjectStructure());
    523     JSModuleEnvironment* moduleEnvironment = JSModuleEnvironment::create(vm, globalObject, nullptr, exportSymbolTable, JSValue(), this);
     530    JSModuleEnvironment* moduleEnvironment = this->moduleEnvironment();
    524531    for (const auto& exp : moduleInformation.exports) {
    525532        JSValue exportedValue;
     
    621628        }
    622629    }
    623 
    624     scope.release();
    625     setModuleEnvironment(globalObject, moduleEnvironment);
    626630}
    627631
  • trunk/Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.h

    r273225 r284702  
    6060
    6161    void prepareLink(VM&, JSWebAssemblyInstance*);
    62     Synchronousness link(JSGlobalObject*, JSValue scriptFetcher, JSObject* importObject, Wasm::CreationMode);
     62    Synchronousness link(JSGlobalObject*, JSValue scriptFetcher);
     63    void initializeImportsAndExports(JSGlobalObject*, JSObject* importObject, Wasm::CreationMode);
    6364    JS_EXPORT_PRIVATE JSValue evaluate(JSGlobalObject*);
    6465
     
    6667
    6768private:
    68     void linkImpl(JSGlobalObject*, JSObject* importObject, Wasm::CreationMode);
    6969    WebAssemblyModuleRecord(VM&, Structure*, const Identifier&);
    7070
Note: See TracChangeset for help on using the changeset viewer.