WebAssembly JavaScript Interface

Editor’s Draft,

This version:
https://webassembly.github.io/spec/js-api/
Latest published version:
https://www.w3.org/TR/wasm-js-api-1/
Issue Tracking:
Inline In Spec
GitHub Issues
Editor:
Daniel Ehrenberg (Igalia)

Abstract

This document provides an explicit JavaScript API for interacting with WebAssembly.

Part of a collection of related documents: the Core WebAssembly Specification, the WebAssembly JS Interface, and the WebAssembly Web API.

Status of this document

This is a public copy of the editors’ draft. It is provided for discussion only and may change at any moment. Its publication here does not imply endorsement of its contents by W3C. Don’t cite this document other than as work in progress.

GitHub Issues are preferred for discussion of this specification. All issues and comments are archived.

This document was produced by the WebAssembly Working Group.

This document was produced by a group operating under the W3C Patent Policy. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.

This document is governed by the 1 February 2018 W3C Process Document.

This API privides a way to access WebAssembly [WEBASSEMBLY] through a bridge to explicitly construct modules from JavaScript [ECMASCRIPT].

See the Issues Index for complete list of issues.

1. Sample API Usage

This section is non-normative.

Given demo.wat (encoded to demo.wasm):

(module
    (import "js" "import1" (func $i1))
    (import "js" "import2" (func $i2))
    (func $main (call $i1))
    (start $main)
    (func (export "f") (call $i2))
)

and the following JavaScript, run in a browser:

var importObj = {js: {
    import1: () => console.log("hello,"),
    import2: () => console.log("world!")
}};
fetch('demo.wasm').then(response =>
    response.arrayBuffer()
).then(buffer =>
    WebAssembly.instantiate(buffer, importObj)
).then(({module, instance}) =>
    instance.exports.f()
);

2. Internal storage

2.1. Interaction of the WebAssembly Store with JavaScript

Note: WebAssembly semantics are defined in terms of an abstract store, representing the state of the WebAssembly abstract machine. WebAssembly operations take a store and return an updated store.

Each agent has an associated store. When a new agent is created, its associated store is set to the result of init_store().

Note: In this specification, no WebAssembly-related objects, memory or addresses can be shared among agents in an agent cluster. In a future version of WebAssembly, this may change.

Elements of the WebAssembly store may be identified with JavaScript values. In particular, each WebAssembly memory instance with a corresponding Memory object is identified with a JavaScript Data Block; modifications to this Data Block are identified to updating the agent’s store to a store which reflects those changes, and vice versa.

2.2. WebAssembly JS Object Caches

Note: There are several WebAssembly objects that may have a corresponding JavaScript object. The correspondence is stored in a per-agent mapping from WebAssembly addresses to JavaScript objects. This mapping is used to ensure that, for a given agent, there exists at most one JavaScript object for a particular WebAssembly address.

Each agent is associated with the following ordered maps:

3. The WebAssembly Namespace

dictionary WebAssemblyInstantiatedSource {
    required Module module;
    required Instance instance;
};

[Exposed=(Window,Worker,Worklet)]
namespace WebAssembly {
    boolean validate(BufferSource bytes);
    Promise<Module> compile(BufferSource bytes);

    Promise<WebAssemblyInstantiatedSource> instantiate(
        BufferSource bytes, optional object importObject);

    Promise<Instance> instantiate(
        Module moduleObject, optional object importObject);
};
To compile a WebAssembly module from a BufferSource bytes, perform the following steps:
  1. Let module be decode_module(bytes). If module is error, return error.

  2. If validate_module(module) is error, return error.

  3. Return module.

The validate(bytes) method, when invoked, performs the following steps:
  1. Compile bytes as a WebAssembly module and store the results as module.

  2. If module is error, return false.

  3. Return true.

A Module object represents a single WebAssembly module. Each Module object has the following internal slots:
To construct a WebAssembly module object from a module module and source bytes bytes, perform the following steps:
  1. Let moduleObject be a new Module object.

  2. Set moduleObject.[[Module]] to module.

  3. Set moduleObject.[[Bytes]] to bytes.

  4. Return moduleObject.

To asynchronously compile a WebAssembly module from a BufferSource bytes, with the promise promise, using optional task source taskSource, perform the following steps:
  1. In parallel, compile the WebAssembly module bytes and store the result as module.

  2. When the above operation completes, queue a task to perform the following steps. If taskSource was provided, queue the task on that task source.

    1. If module is error, reject promise with a CompileError exception.

    2. Otherwise,

      1. Construct a WebAssembly module object from module and bytes, and let moduleObject be the result.

      2. Resolve promise with moduleObject.

The compile(bytes) method, when invoked, performs the following steps:
  1. Let stableBytes be a copy of the bytes held by the buffer bytes.

  2. Let promise be a new promise.

  3. Asynchronously compile a WebAssembly module from stableBytes with promise.

  4. Return promise.

To instantiate a WebAssembly module from a Module moduleObject and imports importObject, perform the following steps:
  1. Let module be moduleObject.[[Module]].

  2. If module.𝗂𝗆𝗉𝗈𝗋𝗍𝗌 is not an empty list, and importObject is undefined, throw a TypeError exception.

  3. Let imports be an empty list of external values.

  4. For each (moduleName, componentName, externtype) in module_imports(module), do

    1. Let o be ? Get(importObject, moduleName).

    2. If Type(o) is not Object, throw a TypeError exception.

    3. Let v be ? Get(o, componentName)

    4. If externtype is of the form 𝖿𝗎𝗇𝖼 functype,

      1. If IsCallable(v) is false, throw a LinkError exception.

      2. If v has a [[FunctionAddress]] internal slot, and therefore is an Exported Function,

        1. Let funcaddr be the value of v’s [[FunctionAddress]] internal slot.

        Note: The signature is checked by instantiate_module invoked below.

      3. Otherwise,

        1. Create a host function from v and let funcaddr be the result.

        2. Let index be the number of external functions in imports. This value index is known as the index of the host function funcaddr.

      4. Let externfunc be the external value 𝖿𝗎𝗇𝖼 funcaddr.

      5. Append externfunc to imports.

    5. If externtype is of the form 𝗀𝗅𝗈𝖻𝖺𝗅 globaltype,

      1. If globaltype is 𝗂𝟨𝟦 or Type(v) is not Number, throw a LinkError exception.

      2. Let value be ToWebAssemblyValue(v, globaltype.valtype)

      3. Assert: globaltype.mut is 𝖼𝗈𝗇𝗌𝗍, as verified by WebAssembly validation.

      4. Let store be the surrounding agent's associated store.

      5. Let (store, globaladdr) be alloc_global(store, globaltype, value).

      6. Set the surrounding agent's associated store to store.

      7. Let externglobal be 𝗀𝗅𝗈𝖻𝖺𝗅 globaladdr.

      8. Append externglobal to imports.

    6. If externtype is of the form 𝗆𝖾𝗆 memtype,

      1. If v is not a Memory object, throw a LinkError exception.

      Note: instantiate_module invoked below will check the imported Memory's size against the importing module’s requirements.

      1. Let externmem be the external value 𝗆𝖾𝗆 v.[[Memory]].

      2. Append externmem to imports.

    7. Otherwise, externtype is of the form 𝗍𝖺𝖻𝗅𝖾 tabletype,

      1. If v is not a Table instance, throw a LinkError exception.

      Note: The table’s length, etc. is checked by instantiate_module invoked below.

      1. Let tableaddr be v.[[Table]]

      2. Let externtable be the external value 𝗍𝖺𝖻𝗅𝖾 tableaddr.

      3. Append externtable to imports.

  5. Let (store, instance) be instantiate_module(store, module, imports).

  6. If instance is error, throw an appropriate exception type:

    • A LinkError exception for most cases which occur during linking.

    • If the error came when running the start function, throw a RuntimeError for most errors which occur from WebAssembly, or the error object propagated from inner ECMAScript code.

    • Another error type if appropriate, for example an out-of-memory exception, as documented in the WebAssembly error mapping.

  7. Let exportsObject be ! ObjectCreate(null).

  8. For each pair (name, externtype) in module_exports(module),

    1. Let externval be get_export(instance, name).

    2. Assert: externval is not error.

    3. If externtype is of the form 𝖿𝗎𝗇𝖼 functype,

      1. Assert: externval is of the form 𝖿𝗎𝗇𝖼 funcaddr.

      2. Let 𝖿𝗎𝗇𝖼 funcaddr be externval.

      3. Let func be the result of creating a new Exported Function from funcaddr.

      4. Let value be func.

    4. If externtype is of the form 𝗀𝗅𝗈𝖻𝖺𝗅 globaltype,

      1. If globaltype.valtype) is 𝗂𝟨𝟦, throw a LinkError exception.

      2. Assert: globaltype.mut is 𝖼𝗈𝗇𝗌𝗍, as verified by WebAssembly validation.

      3. Assert: externval is of the form 𝗀𝗅𝗈𝖻𝖺𝗅 globaladdr.

      4. Let 𝗀𝗅𝗈𝖻𝖺𝗅 globaladdr be externval.

      5. Let value be ToJSValue(read_global(store, globaladdr)).

    5. If externtype is of the form 𝗆𝖾𝗆 memtype,

      1. Assert: externval is of the form 𝗆𝖾𝗆 memaddr.

      2. Let 𝗆𝖾𝗆 memaddr be externval.

      3. Let memory be a new Memory object created from memaddr.

      4. Let value be memory.

    6. Otherwise, externtype is of the form 𝗍𝖺𝖻𝗅𝖾 tabletype,

      1. Assert: externval is of the form 𝗍𝖺𝖻𝗅𝖾 tableaddr.

      2. Let 𝗍𝖺𝖻𝗅𝖾 tableaddr be externval.

      3. Let table be a new Table object created from tableaddr.

      4. Let value be table.

    7. Let status be ! CreateDataProperty(exportsObject, name, value).

    8. Assert: status is true.

    Note: the validity and uniqueness checks performed during WebAssembly module validation ensure that each property name is valid and no properties are defined twice.

  9. Perform ! SetIntegrityLevel(exportsObject, "frozen").

  10. Let instanceObject be a new Instance object whose internal [[Instance]] slot is set to instance and the [[Exports]] slot to exportsObject.

  11. Return instanceObject.

To instantiate a promise of a module promiseOfModule with imports importObject, perform the following steps:
  1. Let promise be a new promise

  2. Upon fulfillment of promiseOfModule with value module:

    1. Instantiate the WebAssembly module module importing importObject, and let instance be the result. If this throws an exception, catch it, reject promise with the exception, and abort these substeps.

    2. Let result be a WebAssemblyInstantiatedSource dictionary with module set to module and instance set to instance.

    3. Resolve promise with result.

  3. Upon rejection of promiseOfModule with reason reason:

    1. Reject promise with reason.

  4. Return promise.

Note: It would be valid to perform certain parts of the instantiation in parallel, but several parts need to happen in the event loop, including JavaScript operations to access the importObject and execution of the start function.

The instantiate(bytes, importObject) method, when invoked, performs the following steps:
  1. Let stableBytes be a copy of the bytes held by the buffer bytes.

  2. Let promiseOfModule be a new promise.

  3. Asynchronously compile a WebAssembly module from stableBytes with promiseOfModule.

  4. Instantiate promiseOfModule with imports importObject and return the result.

The instantiate(moduleObject, importObject) method, when invoked, performs the following steps:
  1. Let promise be a new promise.

  2. Queue a task to perform the following steps:

    1. Instantiate the WebAssembly module module importing importObject, and let instance be the result. If this throws an exception, catch it, and reject promise with the exception.

    2. Resolve promise with instance.

  3. Return promise

Note: A follow-on streaming API is documented in the WebAssembly Web API.

3.1. Modules

enum ImportExportKind {
  "function",
  "table",
  "memory",
  "global"
};

dictionary ModuleExportDescriptor {
  required USVString name;
  required ImportExportKind kind;
  // Note: Other fields such as signature may be added in the future.
};

dictionary ModuleImportDescriptor {
  required USVString module;
  required USVString name;
  required ImportExportKind kind;
};

[LegacyNamespace=WebAssembly, Constructor(BufferSource bytes), Exposed=(Window,Worker,Worklet)]
interface Module {
  static sequence<ModuleExportDescriptor> exports(Module module);
  static sequence<ModuleImportDescriptor> imports(Module module);
  static sequence<ArrayBuffer> customSections(Module module, USVString sectionName);
};
The string value of the extern type type is
The exports(moduleObject) method, when invoked, performs the following steps:
  1. Let module be moduleObject.[[Module]].

  2. Let exports be an empty list.

  3. For each (name, type) in module_exports(module)

    1. Let kind be the string value of the extern type type.

    2. Let obj be a new ModuleExportDescriptor dictionary with name name and kind kind.

    3. Append obj to the end of exports.

  4. Return exports.

The imports(moduleObject) method, when invoked, performs the following steps:
  1. Let module be moduleObject.[[Module]].

  2. Let imports be an empty list.

  3. For each (moduleName, name, type) in module_imports(module),

    1. Let kind be the string value of the extern type type.

    2. Let obj be a new ModuleImportDescriptor dictionary with module moduleName, name name and kind kind.

    3. Append obj to the end of imports.

  4. Return imports.

The customSections(moduleObject, sectionName) method, when invoked, performs the following steps:
  1. Let bytes be moduleObject.[[Bytes]].

  2. Let customSections be an empty list of ArrayBuffers.

  3. For each custom section customSection in the binary format of bytes,

    1. Let name be the name of the custom section, decoded as UTF-8.

    2. Assert: name is not failure (moduleObject.[[Module]] is valid).

    3. If name equals secondName as string values,

      1. Append a new ArrayBuffer containing a copy of the bytes held by the buffer bytes for the range matched by this customsec production.

  4. Return customSections.

The Module(bytes) constructor, when invoked, performs the follwing steps:
  1. Let stableBytes be a copy of the bytes held by the buffer bytes.

  2. Compile the WebAssembly module stableBytes and store the result as module.

  3. If module is error, throw a CompileError exception.

  4. Construct a WebAssembly module object from module and bytes, and return the result.

3.2. Instances

[LegacyNamespace=WebAssembly, Constructor(Module module, optional object importObject), Exposed=(Window,Worker,Worklet)]
interface Instance {
  readonly attribute object exports;
};
The Instance(module, importObject) constructor, when invoked, instantiates the WebAssembly module module importing importObject and returns the result.
The getter of the exports attribute of Instance returns the receiver’s [[Exports]] internal slot.

3.3. Memories

dictionary MemoryDescriptor {
  required [EnforceRange] unsigned long initial;
  [EnforceRange] unsigned long maximum;
};

[LegacyNamespace=WebAssembly, Constructor(MemoryDescriptor descriptor), Exposed=(Window,Worker,Worklet)]
interface Memory {
  unsigned long grow([EnforceRange] unsigned long delta);
  readonly attribute ArrayBuffer buffer;
};
A Memory object represents a single memory instance which can be simultaneously referenced by multiple Instance objects. Each Memory object has the following internal slots:
To create a memory object from a memory address memaddr, perform the following steps:
  1. Let map be the surrounding agent's associated Memory object cache.

  2. If map[memaddr] exists,

    1. Return map[memaddr].

  3. Let block be a Data Block which is identified with the underlying memory of memaddr

  4. Let buffer be a new ArrayBuffer whose [[ArrayBufferData]] is block and [[ArrayBufferByteLength]] is set to the length of block.

  5. Let memory be a new Memory instance with [[Memory]] set to memaddr and [[BufferObject]] set to buffer.

  6. Set map[memaddr] to memory.

  7. Return memory.

Any attempts to detach buffer, other than the detachment performed by grow(delta), will throw a TypeError exception. Specifying this behavior requires changes to the ECMAScript specification.

The Memory(descriptor) constructor, when invoked, performs the following steps:
  1. If descriptor["initial"] is present, let initial be descriptor["initial"]; otherwise, let initial be 0.

  2. If descriptor["maximum"] is present, let maximum be descriptor["maximum"]; otherwise, let maximum be empty.

  3. Let memtype be { min initial, max maximum }

  4. Let store be the surrounding agent's associated store.

  5. Let (store, memaddr) be alloc_mem(store, memtype). If allocation fails, throw a RangeError exception.

  6. Set the surrounding agent's associated store to store.

  7. Create a memory object from the memory address memaddr and return the result.

To reset the Memory buffer of memaddr, perform the following steps:
  1. Let map be the surrounding agent's associated Memory object cache.

  2. Assert: map[memaddr] exists

  3. Let memory be map[memaddr].

  4. Perform ! DetachArrayBuffer(memory.[[BufferObject]]).

  5. Let block be a Data Block which is identified with the underlying memory of memaddr.

  6. Let buffer be a new ArrayBuffer whose [[ArrayBufferData]] is block and [[ArrayBufferByteLength]] is set to the length of block.

  7. Set memory.[[BufferObject]] to buffer.

The grow(delta) method, when invoked, performs the following steps:
  1. Let memory be the Memory instance.

  2. Let store be the surrounding agent's associated store.

  3. Let memaddr be memory.[[Memory]].

  4. Let ret be the size_mem(store, memaddr).

  5. Let store be grow_mem(store, memaddr, delta).

  6. If store is error, throw a RangeError exception.

  7. Set the surrounding agent's associated store to store.

  8. Reset the memory buffer of memaddr.

  9. Return ret.

Immediately after a WebAssembly grow_memory instruction executes, perform the following steps:

  1. If the top of the stack is not 𝗂𝟥𝟤.𝖼𝗈𝗇𝗌𝗍 (−1), then:

    1. Let frame be the current frame.

    2. Assert: due to validation, frame.𝗆𝗈𝖽𝗎𝗅𝖾.𝗆𝖾𝗆𝖺𝖽𝖽𝗋𝗌[0] exists.

    3. Let memaddr be the memory address frame.𝗆𝗈𝖽𝗎𝗅𝖾.𝗆𝖾𝗆𝖺𝖽𝖽𝗋𝗌[0].

    4. Reset the memory buffer of memaddr.

3.4. Tables

enum TableKind {
  "anyfunc",
  // Note: More values may be added in future iterations,
  // e.g., typed function references, typed GC references
};

dictionary TableDescriptor {
  required TableKind element;
  required [EnforceRange] unsigned long initial;
  [EnforceRange] unsigned long maximum;
};

[LegacyNamespace=WebAssembly, Constructor(TableDescriptor descriptor), Exposed=(Window,Worker,Worklet)]
interface Table {
  unsigned long grow([EnforceRange] unsigned long delta);
  Function? get([EnforceRange] unsigned long index);
  void set([EnforceRange] unsigned long index, Function? value);
  readonly attribute unsigned long length;
};
A Table object represents a single table instance which can be simultaneously referenced by multiple Instance objects. Each Table object has the following internal slots:
To create a table object from a table address tableaddr, perform the following steps:
  1. Let map be the surrounding agent's associated Table object cache.

  2. If map[tableaddr] exists,

    1. Return map[tableaddr].

  3. Let values be a list whose length is size_table(store, tableaddr) where each element is null.

  4. Let table be a new Table instance with [[Table]] set to tableaddr and [[Values]] set to values.

  5. Set map[tableaddr] to table.

  6. Return table.

The Table(descriptor) constructor, when invoked, performs the following steps:
  1. If descriptor["initial"] is present, let n be descriptor["initial"]; otherwise, let n be 0.

  2. If descriptor["maximum"] is present, let m be descriptor["maximum"]; otherwise, let m be empty.

  3. If m is not empty and m < n, throw a RangeError exception.

  4. Let type be the table type {𝗆𝗂𝗇 n, 𝗆𝖺𝗑 m} 𝖺𝗇𝗒𝖿𝗎𝗇𝖼.

  5. Let store be the surrounding agent's associated store.

  6. Let (store, tableaddr) be alloc_table(store, type).

  7. Set the surrounding agent's associated store to store.

  8. Create a table object from the table address tableaddr and return the result.

The grow(d) method, when invoked, performs the following steps:
  1. Let tableaddr be the Table instance’s [[Table]] internal slot.

  2. Let initialSize be the length of the Table instance’s [[Values]] internal slot.

  3. Let store be the surrounding agent's associated store.

  4. Let result be grow_table(store, tableaddr, d).

  5. If result is error, throw a RangeError exception.

    Note: The above exception may happen due to either insufficient memory or an invalid size parameter.

  6. Set the surrounding agent's associated store to store.

  7. Append null to the Table instance’s [[Values]] internal slot d times.

  8. Return initialSize.

The getter of the length attribute of Table returns the length of the table’s [[Values]] internal slot.
The get(index) method, when invoked, performs the following steps:
  1. Let values be the Table instance’s [[Values]] internal slot.

  2. Let size be the length of values.

  3. If indexsize, throw a RangeError exception.

  4. Return values[index].

The set(index, value) method, when invoked, performs the following steps:
  1. Let tableaddr be the Table instance’s [[Table]] internal slot.

  2. Let values be the Table instance’s [[Values]] internal slot.

  3. If value is null, let funcaddr be an empty function element.

  4. Otherwise,

    1. If value does not have a [[FunctionAddress]] internal slot, throw a TypeError exception.

    2. Let funcaddr be value.[[FunctionAddress]].

  5. Let store be the surrounding agent's associated store.

  6. Let store be write_table(store, tableaddr, index, funcaddr).

  7. If store is error, throw a RangeError exception.

  8. Set the surrounding agent's associated store to store.

  9. Set values[index] to value.

  10. Return undefined.

3.5. Exported Functions

A WebAssembly function is made available in JavaScript as an Exported Function. Exported Functions are Built-in Function Objects which are not constructors, and which have a [[FunctionAddress]] internal slot. This slot holds a function address relative to the surrounding agent's associated store.

The name of the WebAssembly function funcaddr is found by performing the following steps:
  1. Let store be the surrounding agent's associated store.

  2. Let funcinst be store.𝖿𝗎𝗇𝖼𝗌[funcaddr].

  3. If funcinst is of the form {𝗍𝗒𝗉𝖾 functype, 𝗁𝗈𝗌𝗍𝖼𝗈𝖽𝖾 hostfunc},

    1. Assert: hostfunc is a JavaScript object and IsCallable(hostfunc) is true.

    2. Let index be the index of the host function funcaddr.

  4. Otherwise,

    1. Let moduleinst be funcinst.𝗆𝗈𝖽𝗎𝗅𝖾.

    2. Assert: funcaddr is contained in moduleinst.𝖿𝗎𝗇𝖼𝖺𝖽𝖽𝗋𝗌.

    3. Let index be the index of moduleinst.𝖿𝗎𝗇𝖼𝖺𝖽𝖽𝗋𝗌 where funcaddr is found.

  5. Return ! ToString(index).

To create a new Exported Function from a WebAssembly function address funcaddr, perform the following steps:
  1. Let map be the surrounding agent's associated Exported Function cache.

  2. If map[funcaddr] exists,

    1. Return map[funcaddr].

  3. Let steps be "call the Exported Function funcaddr with arguments."

  4. Let realm be the current Realm.

  5. Let function be CreateBuiltinFunction(realm, steps, %FunctionPrototype%, « [[FunctionAddress]]).

  6. Set function.[[FunctionAddress]] to funcaddr.

  7. Let store be the surrounding agent's associated store.

  8. Let functype be type_func(store, funcaddr).

  9. Let [arguments] → [results] be functype.

  10. Let arity be the length of arguments.

  11. Perform ! DefinePropertyOrThrow(function, "length", PropertyDescriptor {[[Value]]: arity, [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true}).

  12. Let name be the name of the WebAssembly function funcaddr.

  13. Perform ! SetFunctionName(function, name).

  14. Set map[funcaddr] to function.

  15. Return function.

To call an Exported Function with function address funcaddr and a list of JavaScript arguments argValues, perform the following steps:
  1. Let store be the surrounding agent's associated store.

  2. Let functype be type_func(store, funcaddr).

  3. Let [parameters] → [results] be functype.

  4. If parameters or results contains an 𝗂𝟨𝟦, throw a TypeError.

    Note: the above error is thrown each time the [[Call]] method is invoked.

  5. Let args be an empty list of WebAssembly values.

  6. Let i be 0.

  7. For each type t of parameters,

    1. If the length of argValues > i, let arg be argValues[i].

    2. Otherwise, let arg be undefined.

    3. Append ToWebAssemblyValue(arg, t) to args.

    4. Set i to i + 1.

  8. Let (store, ret) be the result of invoke_func(store, funcaddr, args).

  9. Set the surrounding agent's associated store to store.

  10. If ret is error, throw an exception. This exception should be a WebAssembly RuntimeError exception, unless otherwise indicated by the WebAssembly error mapping.

  11. If outArity is 0, return undefined.

  12. Otherwise, return ToJSValue(v), where v is the singular element of ret.

Note: Calling an Exported Function executes in the [[Realm]] of the callee Exported Function, as per the definition of built-in function objects.

Note: Exported Functions do not have a [[Construct]] method and thus it is not possible to call one with the new operator.

To create a host function from the JavaScript object func, perform the following steps:
  1. Let hostfunc be a host function which performs the following steps when called:

    1. If the signature contains an 𝗂𝟨𝟦 (as argument or result), the host function throws a TypeError when called.

    2. Let arguments be a list of the arguments of the invocation of this function.

    3. Let jsArguments be an empty list.

    4. For each arg in arguments,

      1. Append ToJSValue(arg) to jsArguments.

    5. Let ret be ? Call(func, undefined, jsArguments). If an exception is thrown, trigger a WebAssembly trap, and propagate the exception to the enclosing JavaScript.

    6. Let [parameters] → [results] be functype.

    7. If results is empty, return undefined.

    8. Otherwise, return ToWebAssemblyValue(ret, results[0]).

  2. Let store be the surrounding agent's associated store.

  3. Let (store, funcaddr) be alloc_func(store, functype, hostfunc).

  4. Set the surrounding agent's associated store to store.

  5. Return funcaddr

The algorithm ToJSValue(w) coerces a WebAssembly value to a JavaScript value performs the following steps:

Assert: w is not of the form 𝗂𝟨𝟦.𝖼𝗈𝗇𝗌𝗍 i64.

  1. If w is of the form 𝗂𝟥𝟤.𝖼𝗈𝗇𝗌𝗍 i32, return the Number value for signed_32(i32).

  2. If w is of the form 𝖿𝟥𝟤.𝖼𝗈𝗇𝗌𝗍 f32, return the Number value for f32.

  3. If w is of the form 𝖿𝟨𝟦.𝖼𝗈𝗇𝗌𝗍 f64, return the Number value for f64.

Note: Implementations may optionally replace the NaN payload with any other NaN payload at this point in the f32 or f64 cases; such a change would not be observable through NumberToRawBytes.

The algorithm ToWebAssemblyValue(v, type) coerce a JavaScript value to a WebAssembly value performs the following steps:

Assert: type is not 𝗂𝟨𝟦.

  1. If type is 𝗂𝟥𝟤,

    1. Let i32 be ? ToInt32(v).

    2. Return 𝗂𝟥𝟤.𝖼𝗈𝗇𝗌𝗍 i32.

  2. If type is 𝖿𝟥𝟤,

    1. Let f32 be ? ToNumber(v) rounded to the nearest representable value using IEEE 754-2008 round to nearest, ties to even mode.

    2. Return 𝖿𝟥𝟤.𝖼𝗈𝗇𝗌𝗍 f32.

  3. If type is 𝖿𝟨𝟦,

    1. Let f64 be ? ToNumber(v).

    2. Return 𝖿𝟨𝟦.𝖼𝗈𝗇𝗌𝗍 f64.

3.6. Error Objects

WebAssembly defines the following Error classes: CompileError, LinkError, and RuntimeError. WebAssembly errors have the following custom bindings:

[LegacyNamespace=WebAssembly]
interface CompileError { };

[LegacyNamespace=WebAssembly]
interface LinkError { };

[LegacyNamespace=WebAssembly]
interface RuntimeError { };

4. Error Condition Mappings to JavaScript

Running WebAssembly programs encounter certain events which halt execution of the WebAssembly code. WebAssembly code (currently) has no way to catch these conditions and thus an exception will necessarily propagate to the enclosing non-WebAssembly caller (whether it is a browser, JavaScript or another runtime system) where it is handled like a normal JavaScript exception.

If WebAssembly calls JavaScript via import and the JavaScript throws an exception, the exception is propagated through the WebAssembly activation to the enclosing caller.

Because JavaScript exceptions can be handled, and JavaScript can continue to call WebAssembly exports after a trap has been handled, traps do not, in general, prevent future execution.

4.1. Stack Overflow

Whenever a stack overflow occurs in WebAssembly code, the same class of exception is thrown as for a stack overflow in JavaScript. The particular exception here is implementation-defined in both cases.

Note: ECMAScript doesn’t specify any sort of behavior on stack overflow; implementations have been observed to throw RangeError, InternalError or Error. Any is valid here.

4.2. Out of Memory

Whenever validation, compilation or instantiation run out of memory, the same class of exception is thrown as for out of memory conditions in JavaScript. The particular exception here is implementation-defined in both cases.

Note: ECMAScript doesn’t specify any sort of behavior on out-of-memory conditions; implementations have been observed to throw OOMError and to crash. Either is valid here.

5. Integration with ECMAScript modules

WebAssembly modules can be used in a module graph with ECMAScript modules.

WebAssembly Module Records are a subclass of Circular Module Records which contain WebAssembly code. WebAssembly Module Records has one additional internal slot:

To parse a WebAssembly module given a an ArrayBuffer body, a Realm realm and object hostDefined, perform the following steps.
  1. Compile the WebAssembly module stableBytes and store the result as module.

  2. If module is error, throw a CompileError exception.

  3. Construct a WebAssembly module object from module and bytes, and let module be the result.

  4. Let requestedModules be a set.

  5. For each (moduleName, name, type) in module_imports(module.[[Module]]),

    1. Append moduleName to requestedModules.

  6. Return { [[Realm]]: realm, [[Environment]]: undefined, [[Namespace]]: undefined, [[Status]]: "uninstantiated", [[EvaluationError]]: undefined, [[HostDefined]]: hostDefined, [[WebAssemblyModule]]: module, [[RequestedModules]]: requestedModules, [[DFSIndex]]: undefined, [[DFSAncestorIndex]]: undefined }.

The export name list of a WebAssembly Module Record record is defined by the following algorithm:
  1. Let module be record’s [[WebAssemblyModule]] internal slot.

  2. Let exports be an empty list.

  3. For each (name, type) in module_exports(module.[[Module]])

    1. Append name to the end of exports.

  4. Return exports.

WebAssembly Module Records have the following methods:

5.1. GetExportedNames ( exportStarSet ) Concrete Method

  1. Let record be this WebAssembly Module Record.

  2. Return the export name list of record.

5.2. ResolveExport ( exportName, resolveSet ) Concrete Method

  1. Let record be this WebAssembly Module Record.

  2. If the export name list of record contains exportName, return { [[Module]]: record, [[BindingName]]: exportName }.

  3. Otherwise, return null.

5.3. ModuleDeclarationEnvironmentSetup ( ) Concrete Method

  1. Let record be this WebAssembly Module Record.

  2. Let env be NewModuleEnvironment(null).

  3. Set record.[[Environment]] to env.

  4. Let envRec be env’s EnvironmentRecord.

  5. For each name in the export name list of record,

    1. Perform ! envRec.CreateImmutableBinding(name, true).

5.4. ModuleExecution ( ) Concrete Method

  1. Let record be this WebAssembly Module Record.

  2. Let module be record.[[WebAssemblyModule]].

  3. Let imports be a new, empty map.

  4. For each (importedModuleName, name, type) in module_imports(module.[[Module]]),

    1. If imports[importedModuleName] does not exist, set imports[importedModuleName] to a new, empty map.

    2. Let importedModule be ! HostResolveImportedModule(module, importedModuleName).

    3. NOTE: The above call cannot fail because imported module requests are a subset of module.[[RequestedModules]], and these have been resolved earlier in this algorithm.

    4. Let value be ? importedModule.[[Environment]].GetBindingValue(name, true).

    5. Set imports[moduleName][name] to value.

  5. Let importsObject be a new Object.

  6. For each keyvalue of imports,

    1. Let moduleImportsObject be a new Object.

    2. For each importedNameimportedValue of imports,

      1. Perform ! CreateDataPropertyOrThrow(moduleImportsObject, importedName, importedValuealue).

    3. Perform ! CreateDataPropertyOrThrow(importsObject, key, moduleImportsObject).

  7. Instantiate a WebAssembly module module with imports importsObject and let instance be the result.

  8. Let envRec be the EnvironmentRecord of record.[[Environment]].

  9. For each name in the export name list of record,

    1. Perform ! envRec.InitializeBinding(name, ! Get(instance.[[Exports]], name)).

Note: Instantiating the WebAssembly module may yield to the task queue and is not guaranteed to be synchronous.

5.5. Modifications to HTML

The fetch a single module script algorithm, in Step 9, would switch off of the mimetype. If the response has a JavaScript mimetype, continue the algorithm. If it has a non-wasm mimetype, abort the algorithm. If it has an application/wasm mimetype, perform the following steps:

  1. Let source be response’s body as an ArrayBuffer

  2. Create a module script, but with step 7 replacing ParseModule with the parse a WebAssembly Module algorithm.

  3. Set moduleMap[url] to to module

TODO: Write this up as a PR against the HTML spec.

Conformance

Document conventions

Conformance requirements are expressed with a combination of descriptive assertions and RFC 2119 terminology. The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in the normative parts of this document are to be interpreted as described in RFC 2119. However, for readability, these words do not appear in all uppercase letters in this specification.

All of the text of this specification is normative except sections explicitly marked as non-normative, examples, and notes. [RFC2119]

Examples in this specification are introduced with the words “for example” or are set apart from the normative text with class="example", like this:

This is an example of an informative example.

Informative notes begin with the word “Note” and are set apart from the normative text with class="note", like this:

Note, this is an informative note.

Index

Terms defined by this specification

Terms defined by reference

References

Normative References

[CSS-VALUES-3]
Tab Atkins Jr.; Elika Etemad. CSS Values and Units Module Level 3. 29 September 2016. CR. URL: https://www.w3.org/TR/css-values-3/
[ECMASCRIPT]
ECMAScript Language Specification. URL: https://tc39.github.io/ecma262/
[ENCODING]
Anne van Kesteren. Encoding Standard. Living Standard. URL: https://encoding.spec.whatwg.org/
[HTML]
Anne van Kesteren; et al. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra Standard. Living Standard. URL: https://infra.spec.whatwg.org/
[PROMISES-GUIDE]
Domenic Denicola. Writing Promise-Using Specifications. 16 February 2016. Finding of the W3C TAG. URL: https://www.w3.org/2001/tag/doc/promises-guide
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://tools.ietf.org/html/rfc2119
[URL]
Anne van Kesteren. URL Standard. Living Standard. URL: https://url.spec.whatwg.org/
[WEBASSEMBLY]
WebAssembly Core Specification. Draft. URL: https://webassembly.github.io/spec/core/
[WebIDL]
Cameron McCormack; Boris Zbarsky; Tobie Langel. Web IDL. 15 December 2016. ED. URL: https://heycam.github.io/webidl/

IDL Index

dictionary WebAssemblyInstantiatedSource {
    required Module module;
    required Instance instance;
};

[Exposed=(Window,Worker,Worklet)]
namespace WebAssembly {
    boolean validate(BufferSource bytes);
    Promise<Module> compile(BufferSource bytes);

    Promise<WebAssemblyInstantiatedSource> instantiate(
        BufferSource bytes, optional object importObject);

    Promise<Instance> instantiate(
        Module moduleObject, optional object importObject);
};

enum ImportExportKind {
  "function",
  "table",
  "memory",
  "global"
};

dictionary ModuleExportDescriptor {
  required USVString name;
  required ImportExportKind kind;
  // Note: Other fields such as signature may be added in the future.
};

dictionary ModuleImportDescriptor {
  required USVString module;
  required USVString name;
  required ImportExportKind kind;
};

[LegacyNamespace=WebAssembly, Constructor(BufferSource bytes), Exposed=(Window,Worker,Worklet)]
interface Module {
  static sequence<ModuleExportDescriptor> exports(Module module);
  static sequence<ModuleImportDescriptor> imports(Module module);
  static sequence<ArrayBuffer> customSections(Module module, USVString sectionName);
};

[LegacyNamespace=WebAssembly, Constructor(Module module, optional object importObject), Exposed=(Window,Worker,Worklet)]
interface Instance {
  readonly attribute object exports;
};

dictionary MemoryDescriptor {
  required [EnforceRange] unsigned long initial;
  [EnforceRange] unsigned long maximum;
};

[LegacyNamespace=WebAssembly, Constructor(MemoryDescriptor descriptor), Exposed=(Window,Worker,Worklet)]
interface Memory {
  unsigned long grow([EnforceRange] unsigned long delta);
  readonly attribute ArrayBuffer buffer;
};

enum TableKind {
  "anyfunc",
  // Note: More values may be added in future iterations,
  // e.g., typed function references, typed GC references
};

dictionary TableDescriptor {
  required TableKind element;
  required [EnforceRange] unsigned long initial;
  [EnforceRange] unsigned long maximum;
};

[LegacyNamespace=WebAssembly, Constructor(TableDescriptor descriptor), Exposed=(Window,Worker,Worklet)]
interface Table {
  unsigned long grow([EnforceRange] unsigned long delta);
  Function? get([EnforceRange] unsigned long index);
  void set([EnforceRange] unsigned long index, Function? value);
  readonly attribute unsigned long length;
};

[LegacyNamespace=WebAssembly]
interface CompileError { };

[LegacyNamespace=WebAssembly]
interface LinkError { };

[LegacyNamespace=WebAssembly]
interface RuntimeError { };

Issues Index

Any attempts to detach buffer, other than the detachment performed by grow(delta), will throw a TypeError exception. Specifying this behavior requires changes to the ECMAScript specification.