| <pre class='metadata'> |
| Title: WebAssembly JavaScript Interface |
| Shortname: wasm-js-api |
| Group: wasm |
| Status: ED |
| Level: 1 |
| TR: https://www.w3.org/TR/wasm-js-api-1/ |
| ED: https://webassembly.github.io/spec/js-api/ |
| Editor: Daniel Ehrenberg (Igalia) |
| Repository: WebAssembly/spec |
| Markup Shorthands: css no, markdown yes |
| Abstract: This document provides an explicit JavaScript API for interacting with WebAssembly. |
| Prepare For TR: true |
| </pre> |
| |
| <pre class='biblio'> |
| { |
| "WEBASSEMBLY": { |
| "href": "https://webassembly.github.io/spec/core/", |
| "title": "WebAssembly Core Specification", |
| "publisher": "W3C WebAssembly Community Group", |
| "status": "Draft" |
| } |
| } |
| </pre> |
| |
| <pre class="anchors"> |
| urlPrefix: https://tc39.github.io/ecma262/; spec: ECMASCRIPT |
| type: interface; for: ECMAScript |
| text: ArrayBuffer; url: sec-arraybuffer-objects |
| type: exception; for: ECMAScript |
| text: Error; url: sec-error-objects |
| text: NativeError; url: sec-nativeerror-constructors |
| text: TypeError; url: sec-native-error-types-used-in-this-standard-typeerror |
| text: RangeError; url: sec-native-error-types-used-in-this-standard-rangeerror |
| type: dfn |
| text: agent cluster; url: sec-agent-clusters |
| text: agent; url: agent |
| text: data block; url: sec-data-blocks |
| text: Bound Function; url: sec-bound-function-exotic-objects |
| text: NumericLiteral; url: sec-literals-numeric-literals |
| text: surrounding agent; url: surrounding-agent |
| text: ToNumber; url: sec-tonumber |
| text: ToInt32; url: sec-toint32 |
| text: ToString; url: sec-tostring |
| url: sec-ecmascript-data-types-and-values |
| text: Type |
| text: Type(x) |
| url: sec-iscallable |
| text: IsCallable |
| text: callable; for: ECMAScript |
| url: sec-well-known-intrinsic-objects |
| text: %ErrorPrototype% |
| text: %ObjectPrototype%; url: sec-properties-of-the-object-prototype-object |
| text: %FunctionPrototype%; url: sec-properties-of-the-function-prototype-object |
| text: %Promise%; url: sec-promise-constructor |
| text: Property Descriptor; url: sec-property-descriptor-specification-type |
| text: array index; url: sec-array-exotic-objects |
| text: OrdinaryGetOwnProperty; url: sec-ordinarygetownproperty |
| text: OrdinaryDefineOwnProperty; url: sec-ordinarydefineownproperty |
| text: OrdinaryPreventExtensions; url: sec-ordinarypreventextensions |
| text: OrdinarySet; url: sec-ordinaryset |
| text: equally close values; url: sec-ecmascript-language-types-number-type |
| text: internal slot; url: sec-object-internal-methods-and-internal-slots |
| text: JavaScript execution context stack; url: execution-context-stack |
| text: running JavaScript execution context; url: running-execution-context |
| text: GetIterator; url: sec-getiterator |
| text: IteratorStep; url: sec-iteratorstep |
| text: NormalCompletion; url: sec-normalcompletion |
| text: IteratorValue; url: sec-iteratorvalue |
| url: sec-well-known-symbols |
| text: @@iterator |
| text: @@toStringTag |
| text: CreateDataProperty; url: sec-createdataproperty |
| text: DetachArrayBuffer; url: sec-detacharraybuffer |
| text: SetIntegrityLevel; url: sec-setintegritylevel |
| text: Call; url: sec-call |
| text: Get; url: sec-get-o-p |
| text: DefinePropertyOrThrow; url: sec-definepropertyorthrow |
| text: current Realm; url: current-realm |
| text: ObjectCreate; url: sec-objectcreate |
| text: CreateBuiltinFunction; url: sec-createbuiltinfunction |
| text: SetFunctionName; url: sec-setfunctionname |
| text: SetFunctionLength; url: sec-setfunctionlength |
| text: the Number value; url: sec-ecmascript-language-types-number-type |
| text: NumberToRawBytes; url: sec-numbertorawbytes |
| text: Built-in Function Objects; url: sec-built-in-function-objects |
| urlPrefix: https://webassembly.github.io/spec/core/; spec: WebAssembly; type: dfn |
| url: valid/modules.html#valid-module |
| text: valid |
| text: WebAssembly module validation |
| text: module grammar; url: binary/modules.html#binary-module |
| text: custom section; url: binary/modules.html#custom-section |
| text: customsec; url: binary/modules.html#binary-customsec |
| text: memory instance; url: exec/runtime.html#memory-instances |
| text: table instance; url: exec/runtime.html#table-instances |
| text: global instance; url: exec/runtime.html#global-instances |
| text: trap; url: exec/runtime.html#syntax-trap |
| url: exec/runtime.html#values |
| text: WebAssembly value |
| text: ππ¨π¦.πΌππππ |
| text: ππ₯π€.πΌππππ |
| text: πΏπ₯π€.πΌππππ |
| text: πΏπ¨π¦.πΌππππ |
| text: function index; url: syntax/modules.html#syntax-funcidx |
| text: function instance; url: exec/runtime.html#function-instances |
| text: store_init; url: appendix/embedding.html#embed-store-init |
| text: module_decode; url: appendix/embedding.html#embed-module-decode |
| text: module_validate; url: appendix/embedding.html#embed-module-validate |
| text: module_instantiate; url: appendix/embedding.html#embed-module-instantiate |
| text: module_imports; url: appendix/embedding.html#embed-module-imports |
| text: module_exports; url: appendix/embedding.html#embed-module-exports |
| text: instance_export; url: appendix/embedding.html#embed-instance-export |
| text: func_alloc; url: appendix/embedding.html#embed-func-alloc |
| text: func_type; url: appendix/embedding.html#embed-func-type |
| text: func_invoke; url: appendix/embedding.html#embed-func-invoke |
| text: table_alloc; url: appendix/embedding.html#embed-table-alloc |
| text: table_type; url: appendix/embedding.html#embed-table-type |
| text: table_read; url: appendix/embedding.html#embed-table-read |
| text: table_write; url: appendix/embedding.html#embed-table-write |
| text: table_size; url: appendix/embedding.html#embed-table-size |
| text: table_grow; url: appendix/embedding.html#embed-table-grow |
| text: mem_alloc; url: appendix/embedding.html#embed-mem-alloc |
| text: mem_type; url: appendix/embedding.html#embed-mem-type |
| text: mem_read; url: appendix/embedding.html#embed-mem-read |
| text: mem_write; url: appendix/embedding.html#embed-mem-write |
| text: mem_size; url: appendix/embedding.html#embed-mem-size |
| text: mem_grow; url: appendix/embedding.html#embed-mem-grow |
| text: global_alloc; url: appendix/embedding.html#embed-global-alloc |
| text: global_type; url: appendix/embedding.html#embed-global-type |
| text: global_read; url: appendix/embedding.html#embed-global-read |
| text: global_write; url: appendix/embedding.html#embed-global-write |
| text: error; url: appendix/embedding.html#embed-error |
| text: store; url: exec/runtime.html#syntax-store |
| text: table type; url: syntax/types.html#syntax-tabletype |
| text: table address; url: exec/runtime.html#syntax-tableaddr |
| text: function address; url: exec/runtime.html#syntax-funcaddr |
| text: memory address; url: exec/runtime.html#syntax-memaddr |
| text: global address; url: exec/runtime.html#syntax-globaladdr |
| url: syntax/types.html#syntax-valtype |
| text: ππ₯π€ |
| text: ππ¨π¦ |
| text: πΏπ₯π€ |
| text: πΏπ¨π¦ |
| text: function element; url: exec/runtime.html#syntax-funcelem |
| text: import component; url: syntax/modules.html#imports |
| text: external value; url: exec/runtime.html#syntax-externval |
| text: host function; url: exec/runtime.html#syntax-hostfunc |
| text: the instantiation algorithm; url: exec/modules.html#instantiation |
| text: module; url: syntax/modules.html#syntax-module |
| text: πππππππ; url: syntax/modules.html#syntax-module |
| url: syntax/types.html#external-types |
| text: external type |
| text: πΏπππΌ |
| text: ππΊπ»π
πΎ |
| text: ππΎπ |
| text: ππ
ππ»πΊπ
|
| text: global type; url: syntax/types.html#syntax-globaltype |
| url: syntax/types.html#syntax-mut |
| text: var |
| text: const |
| text: address; url: exec/runtime.html#addresses |
| text: signed_32; url: exec/numerics.html#aux-signed |
| text: memory.grow; url: exec/instructions.html#exec-memory-grow |
| text: current frame; url: exec/conventions.html#exec-notation-textual |
| text: πππ½ππ
πΎ; url: exec/runtime.html#syntax-frame |
| text: ππΎππΊπ½π½ππ; url: exec/runtime.html#syntax-moduleinst |
| text: sequence; url: syntax/conventions.html#grammar-notation |
| </pre> |
| |
| <pre class='link-defaults'> |
| spec:infra; type:dfn; text:list |
| spec:ecma-262; type:exception; for:ECMAScript; text:Error |
| spec:infra; type:dfn; for:set; text:append |
| spec:ecmascript; type:exception; for:ECMAScript; text:TypeError |
| spec:ecmascript; type:exception; for:ECMAScript; text:RangeError |
| spec:ecmascript; type:interface; for:ECMAScript; text:ArrayBuffer |
| spec:promises-guide-1; type:dfn; text:resolve |
| </pre> |
| |
| This API privides a way to access WebAssembly [[WEBASSEMBLY]] through a bridge to explicitly construct modules from JavaScript [[ECMASCRIPT]]. |
| |
| <h2 id="sample">Sample API Usage</h2> |
| |
| <p><em>This section is non-normative.</em></p> |
| |
| Given `demo.wat` (encoded to `demo.wasm`): |
| |
| ```lisp |
| (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: |
| |
| ```javascript |
| 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() |
| ); |
| ``` |
| |
| <h2 id="webassembly-storage">Internal storage</h2> |
| |
| <h3 id="store">Interaction of the WebAssembly Store with JavaScript</h3> |
| |
| 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 <dfn>associated store</dfn>. 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 <dfn>identified with</dfn> 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. |
| |
| <h3 id="object-caches">WebAssembly JS Object Caches</h3> |
| |
| Note: There are several WebAssembly objects that may have a corresponding JavaScript object. The correspondence is stored in a per-agent mapping from WebAssembly [=address=]es 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 map=]s: |
| * The <dfn>Memory object cache</dfn>, mapping [=memory address=]es to {{Memory}} objects. |
| * The <dfn>Table object cache</dfn>, mapping [=table address=]es to {{Table}} objects. |
| * The <dfn>Exported Function cache</dfn>, mapping [=function address=]es to [=Exported Function=] objects. |
| * The <dfn>Global object cache</dfn>, mapping [=global address=]es to {{Global}} objects. |
| |
| <h2 id="webassembly-namespace">The WebAssembly Namespace</h2> |
| |
| <pre class="idl"> |
| 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); |
| }; |
| </pre> |
| |
| <!-- |
| Should we include notes describing what the functions do, as the HTML spec does? It could look like this: |
| |
| Note: |
| WebAssembly.validate(|bytes|) synchronously validates bytes of WebAssembly, returning true if the validation was successful. |
| WebAssembly.compile(|bytes|) asynchronously validates and complies bytes of WebAssembly into a Module. |
| WebAssembly.instantiate(|bytes|, |importObject|) asynchronously compiles and instantiates a WebAssembly module from bytes of source. |
| The WebAssembly.instantiate(|moduleObject|, |importObject|) asynchronously instantiates a compiled module. |
| --> |
| |
| <div algorithm> |
| To <dfn>compile a WebAssembly module</dfn> from source bytes |bytes|, perform the following steps: |
| 1. Let |module| be [=module_decode=](|bytes|). If |module| is [=error=], return [=error=]. |
| 1. If [=module_validate=](|module|) is [=error=], return [=error=]. |
| 1. Return |module|. |
| </div> |
| |
| <div algorithm> |
| The <dfn method for="WebAssembly">validate(|bytes|)</dfn> method, when invoked, performs the following steps: |
| 1. Let |stableBytes| be a [=get a copy of the buffer source|copy of the bytes held by the buffer=] |bytes|. |
| 1. [=Compile a WebAssembly module|Compile=] |stableBytes| as a WebAssembly module and store the results as |module|. |
| 1. If |module| is [=error=], return false. |
| 1. Return true. |
| </div> |
| |
| <div> |
| A {{Module}} object represents a single WebAssembly module. Each {{Module}} object has the following internal slots: |
| |
| * \[[Module]] : a WebAssembly [=module=] |
| * \[[Bytes]] : the source bytes of \[[Module]]. |
| </div> |
| |
| <div algorithm> |
| To <dfn>construct a WebAssembly module object</dfn> from a module |module| and source bytes |bytes|, perform the following steps: |
| |
| 1. Let |moduleObject| be a new {{Module}} object. |
| 1. Set |moduleObject|.\[[Module]] to |module|. |
| 1. Set |moduleObject|.\[[Bytes]] to |bytes|. |
| 1. Return |moduleObject|. |
| </div> |
| |
| <div algorithm> |
| To <dfn>asynchronously compile a WebAssembly module</dfn> from source bytes |bytes|, using optional [=task source=] |taskSource|, perform the following steps: |
| |
| 1. Let |promise| be [=a new promise=]. |
| 1. Run the following steps [=in parallel=]: |
| 1. [=compile a WebAssembly module|Compile the WebAssembly module=] |bytes| and store the result as |module|. |
| 1. [=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. |
| 1. Otherwise, |
| 1. [=Construct a WebAssembly module object=] from |module| and |bytes|, and let |moduleObject| be the result. |
| 1. [=Resolve=] |promise| with |moduleObject|. |
| 1. Return |promise|. |
| </div> |
| |
| <div algorithm> |
| The <dfn method for="WebAssembly">compile(|bytes|)</dfn> method, when invoked, performs the following steps: |
| 1. Let |stableBytes| be a [=get a copy of the buffer source|copy of the bytes held by the buffer=] |bytes|. |
| 1. [=Asynchronously compile a WebAssembly module=] from |stableBytes| and return the result. |
| </div> |
| |
| <div algorithm="read-the-imports"> |
| To <dfn>read the imports</dfn> from a WebAssembly module |module| from imports object |importObject|, perform the following steps: |
| 1. If |module|.[=πππππππ=] is not an empty list, and |importObject| is undefined, throw a {{TypeError}} exception. |
| 1. Let |imports| be an empty [=list=] of [=external value=]s. |
| 1. For each (|moduleName|, |componentName|, |externtype|) in [=module_imports=](|module|), do |
| 1. Let |o| be ? [=Get=](|importObject|, |moduleName|). |
| 1. If [=Type=](|o|) is not [=Object=], throw a {{TypeError}} exception. |
| 1. Let |v| be ? [=Get=](|o|, |componentName|) |
| 1. If |externtype| is of the form [=πΏπππΌ=] |functype|, |
| 1. If [=IsCallable=](|v|) is false, throw a {{LinkError}} exception. |
| 1. 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 [=module_instantiate=] invoked below. |
| 1. Otherwise, |
| 1. [=Create a host function=] from |v| and |functype|, and let |funcaddr| be the result. |
| 1. Let |index| be the number of external functions in |imports|. This value |index| is known as the <dfn>index of the host function</dfn> |funcaddr|. |
| 1. Let |externfunc| be the [=external value=] [=external value|πΏπππΌ=] |funcaddr|. |
| 1. [=Append=] |externfunc| to |imports|. |
| 1. If |externtype| is of the form [=ππ
ππ»πΊπ
=] <var ignore>mut</var> |valtype|, |
| 1. If [=Type=](|v|) is [=Number=], |
| 1. If |valtype| is [=ππ¨π¦=], throw a {{LinkError}} exception. |
| 1. Let |value| be [=ToWebAssemblyValue=](|v|, |valtype|) |
| 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. |
| 1. Let (|store|, |globaladdr|) be [=global_alloc=](|store|, [=const=] |valtype|, |value|). |
| 1. Set the [=surrounding agent=]'s [=associated store=] to |store|. |
| 1. If |v| is a {{Global}} instance, |
| 1. Let |globaladdr| be |v|.\[[Global]] |
| 1. Otherwise, |
| 1. Throw a {{LinkError}} exception. |
| 1. Let |externglobal| be [=external value|ππ
ππ»πΊπ
=] |globaladdr|. |
| 1. [=Append=] |externglobal| to |imports|. |
| 1. If |externtype| is of the form [=ππΎπ=] <var ignore>memtype</var>, |
| 1. If |v| is not a {{Memory}} object, throw a {{LinkError}} exception. |
| 1. Note: [=module_instantiate=] invoked below will check the imported {{Memory}}'s size against the importing module's requirements. |
| 1. Let |externmem| be the [=external value=] [=external value|ππΎπ=] |v|.\[[Memory]]. |
| 1. [=Append=] |externmem| to |imports|. |
| 1. Otherwise, |externtype| is of the form [=ππΊπ»π
πΎ=] <var ignore>tabletype</var>, |
| 1. If |v| is not a {{Table}} instance, throw a {{LinkError}} exception. |
| 1. Note: The table's length, etc. is checked by [=module_instantiate=] invoked below. |
| 1. Let |tableaddr| be |v|.\[[Table]] |
| 1. Let |externtable| be the [=external value=] [=external value|ππΊπ»π
πΎ=] |tableaddr|. |
| 1. [=Append=] |externtable| to |imports|. |
| 1. Return |imports|. |
| </div> |
| |
| <div algorithm> |
| To <dfn>create an instance object</dfn> from a WebAssembly module |module| and instance |instance|, perform the following steps: |
| 1. Let |exportsObject| be ! [=ObjectCreate=](null). |
| 1. For each pair (|name|, |externtype|) in [=module_exports=](|module|), |
| 1. Let |externval| be [=instance_export=](|instance|, |name|). |
| 1. Assert: |externval| is not [=error=]. |
| 1. If |externtype| is of the form [=πΏπππΌ=] <var ignore>functype</var>, |
| 1. Assert: |externval| is of the form [=external value|πΏπππΌ=] |funcaddr|. |
| 1. Let [=external value|πΏπππΌ=] |funcaddr| be |externval|. |
| 1. Let |func| be the result of creating [=a new Exported Function=] from |funcaddr|. |
| 1. Let |value| be |func|. |
| 1. If |externtype| is of the form [=ππ
ππ»πΊπ
=] <var ignore>globaltype</var>, |
| 1. Assert: |externval| is of the form [=external value|ππ
ππ»πΊπ
=] |globaladdr|. |
| 1. Let [=external value|ππ
ππ»πΊπ
=] |globaladdr| be |externval|. |
| 1. Let |global| be [=create a global object|a new Global object=] created from |globaladdr|. |
| 1. Let |value| be |global|. |
| 1. If |externtype| is of the form [=ππΎπ=] <var ignore>memtype</var>, |
| 1. Assert: |externval| is of the form [=external value|ππΎπ=] |memaddr|. |
| 1. Let [=external value|ππΎπ=] |memaddr| be |externval|. |
| 1. Let |memory| be [=create a memory object|a new Memory object=] created from |memaddr|. |
| 1. Let |value| be |memory|. |
| 1. Otherwise, |externtype| is of the form [=ππΊπ»π
πΎ=] <var ignore>tabletype</var>, |
| 1. Assert: |externval| is of the form [=external value|ππΊπ»π
πΎ=] |tableaddr|. |
| 1. Let [=external value|ππΊπ»π
πΎ=] |tableaddr| be |externval|. |
| 1. Let |table| be [=create a Table object|a new Table object=] created from |tableaddr|. |
| 1. Let |value| be |table|. |
| 1. Let |status| be ! [=CreateDataProperty=](|exportsObject|, |name|, |value|). |
| 1. 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. |
| 1. Perform ! [=SetIntegrityLevel=](|exportsObject|, `"frozen"`). |
| 1. Return a new {{Instance}} object whose internal \[[Instance]] slot is set to |instance| and the \[[Exports]] slot to |exportsObject|. |
| </div> |
| |
| <div algorithm> |
| To <dfn>instantiate the core of a WebAssembly module</dfn> from a module |module| and imports |imports|, perform the following steps: |
| 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. |
| 1. Let |result| be [=module_instantiate=](|store|, |module|, |imports|). |
| 1. If |result| 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 <a href="#errors">the WebAssembly error mapping</a>. |
| 1. Let (|store|, |instance|) be |result|. |
| 1. Set the [=surrounding agent=]'s [=associated store=] to |store|. |
| 1. Return |instance|. |
| </div> |
| |
| <div algorithm> |
| To <dfn>asynchronously instantiate a WebAssembly module</dfn> from a {{Module}} |moduleObject| and imports |importObject|, perform the following steps: |
| 1. Let |promise| be [=a new promise=]. |
| 1. Let |module| be |moduleObject|.\[[Module]]. |
| 1. [=Read the imports=] of |module| with imports |importObject|, and let |imports| be the result. |
| If this operation throws an exception, catch it, [=reject=] |promise| with the exception, and return |promise|. |
| 1. [=Queue a task=] to perform the following steps: |
| 1. [=Instantiate the core of a WebAssembly module=] |module| with |imports|, and let |instance| be the result. |
| If this throws an exception, catch it, [=reject=] |promise| with the exception, and terminate these substeps. |
| 1. [=Create an instance object=] from |module| and |instance|, and let the result be |instanceObject|. |
| If this throws an exception, catch it, [=reject=] |promise| with the exception, and terminate these substeps. |
| 1. [=Resolve=] |promise| with |instanceObject|. |
| 1. Return |promise|. |
| </div> |
| |
| <div algorithm="instantiate"> |
| To <dfn>instantiate a WebAssembly module</dfn> from a {{Module}} |moduleObject| and imports |importObject|, perform the following steps: |
| 1. Let |module| be |moduleObject|.\[[Module]]. |
| 1. [=Read the imports=] of |module| with imports |importObject|, and let |imports| be the result. |
| 1. [=Instantiate the core of a WebAssembly module=] |module| with |imports|, and let |instance| be the result. |
| 1. [=Create an instance object=] from |module| and |instance|, and let the result be |instanceObject|. |
| 1. Return |instanceObject|. |
| </div> |
| |
| <div algorithm> |
| To <dfn>instantiate a promise of a module</dfn> |promiseOfModule| with imports |importObject|, perform the following steps: |
| |
| 1. Let |promise| be [=a new promise=] |
| 1. [=Upon fulfillment=] of |promiseOfModule| with value |module|: |
| 1. [=instantiate a WebAssembly module|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. |
| 1. Let |result| be a {{WebAssemblyInstantiatedSource}} dictionary with {{WebAssemblyInstantiatedSource/module}} set to |module| and {{WebAssemblyInstantiatedSource/instance}} set to |instance|. |
| 1. [=Resolve=] |promise| with |result|. |
| 1. [=Upon rejection=] of |promiseOfModule| with reason |reason|: |
| 1. [=Reject=] |promise| with |reason|. |
| 1. 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. |
| </div> |
| |
| <div algorithm> |
| The <dfn method for="WebAssembly">instantiate(|bytes|, |importObject|)</dfn> method, when invoked, performs the following steps: |
| 1. Let |stableBytes| be a [=get a copy of the buffer source|copy of the bytes held by the buffer=] |bytes|. |
| 1. [=Asynchronously compile a WebAssembly module=] from |stableBytes| and let |promiseOfModule| be the result. |
| 1. [=Instantiate a promise of a module|Instantiate=] |promiseOfModule| with imports |importObject| and return the result. |
| </div> |
| |
| <div algorithm> |
| The <dfn method for="WebAssembly">instantiate(|moduleObject|, |importObject|)</dfn> method, when invoked, performs the following steps: |
| 1. [=asynchronously instantiate a WebAssembly module|Asynchronously instantiate the WebAssembly module=] |moduleObject| importing |importObject|, and return the result. |
| </div> |
| |
| Note: A follow-on streaming API is documented in the <a href="https://webassembly.github.io/spec/web-api/index.html">WebAssembly Web API</a>. |
| |
| <h3 id="modules">Modules</h3> |
| |
| <pre class="idl"> |
| 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 moduleObject); |
| static sequence<ModuleImportDescriptor> imports(Module moduleObject); |
| static sequence<ArrayBuffer> customSections(Module moduleObject, DOMString sectionName); |
| }; |
| </pre> |
| |
| <div algorithm> |
| The <dfn>string value of the extern type</dfn> |type| is |
| * "function" if |type| is of the form [=πΏπππΌ=] functype |
| * "table" if |type| is of the form [=ππΊπ»π
πΎ=] tabletype |
| * "memory" if |type| is of the form [=ππΎπ=] memtype |
| * "global" if |type| is of the form [=ππ
ππ»πΊπ
=] globaltype |
| </div> |
| |
| <div algorithm> |
| The <dfn method for="Module">exports(|moduleObject|)</dfn> method, when invoked, performs the following steps: |
| 1. Let |module| be |moduleObject|.\[[Module]]. |
| 1. Let |exports| be an empty [=list=]. |
| 1. For each (|name|, |type|) in [=module_exports=](|module|) |
| 1. Let |kind| be the [=string value of the extern type=] |type|. |
| 1. Let |obj| be a new {{ModuleExportDescriptor}} dictionary with {{ModuleExportDescriptor/name}} |name| and {{ModuleExportDescriptor/kind}} |kind|. |
| 1. [=Append=] |obj| to the end of |exports|. |
| 1. Return |exports|. |
| </div> |
| |
| <div algorithm> |
| The <dfn method for="Module">imports(|moduleObject|)</dfn> method, when invoked, performs the following steps: |
| 1. Let |module| be |moduleObject|.\[[Module]]. |
| 1. Let |imports| be an empty [=list=]. |
| 1. For each (|moduleName|, |name|, |type|) in [=module_imports=](|module|), |
| 1. Let |kind| be the [=string value of the extern type=] |type|. |
| 1. Let |obj| be a new {{ModuleImportDescriptor}} dictionary with {{ModuleImportDescriptor/module}} |moduleName|, {{ModuleImportDescriptor/name}} |name| and {{ModuleImportDescriptor/kind}} |kind|. |
| 1. [=Append=] |obj| to the end of |imports|. |
| 1. Return |imports|. |
| </div> |
| |
| <div algorithm> |
| The <dfn method for="Module">customSections(|moduleObject|, |sectionName|)</dfn> method, when invoked, performs the following steps: |
| 1. Let |bytes| be |moduleObject|.\[[Bytes]]. |
| 1. Let |customSections| be an empty [=list=] of {{ArrayBuffer}}s. |
| 1. For each [=custom section=] |customSection| in |bytes|, interpreted according to the [=module grammar=], |
| 1. Let |name| be the <code>name</code> of |customSection|, [=UTF-8 decode without BOM or fail|decoded as UTF-8=]. |
| 1. Assert: |name| is not failure (|moduleObject|.\[[Module]] is [=valid=]). |
| 1. If |name| equals |sectionName| as string values, |
| 1. [=Append=] a new {{ArrayBuffer}} containing a copy of the bytes in |bytes| for the range matched by this [=customsec=] production. |
| 1. Return |customSections|. |
| </div> |
| |
| <div algorithm> |
| The <dfn constructor for="Module">Module(|bytes|)</dfn> constructor, when invoked, performs the follwing steps: |
| |
| 1. Let |stableBytes| be a [=get a copy of the buffer source|copy of the bytes held by the buffer=] |bytes|. |
| 1. [=Compile a WebAssembly module|Compile the WebAssembly module=] |stableBytes| and store the result as |module|. |
| 1. If |module| is [=error=], throw a {{CompileError}} exception. |
| 1. [=Construct a WebAssembly module object=] from |module| and |stableBytes|, and return the result. |
| </div> |
| |
| <h3 id="instances">Instances</h3> |
| |
| <pre class="idl"> |
| [LegacyNamespace=WebAssembly, Constructor(Module module, optional object importObject), Exposed=(Window,Worker,Worklet)] |
| interface Instance { |
| readonly attribute object exports; |
| }; |
| </pre> |
| |
| <div algorithm> |
| The <dfn constructor for="Instance">Instance(|module|, |importObject|)</dfn> constructor, when invoked, [=instantiate a WebAssembly module|instantiates the WebAssembly module=] |module| importing |importObject| and returns the result. |
| </div> |
| |
| <div algorithm> |
| The getter of the <dfn attribute for="Instance">exports</dfn> attribute of {{Instance}} returns the receiver's \[[Exports]] internal slot. |
| </div> |
| |
| <h3 id="memories">Memories</h3> |
| |
| <pre class="idl"> |
| 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; |
| }; |
| </pre> |
| |
| <div> |
| 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: |
| |
| * \[[Memory]] : a [=memory address=] |
| * \[[BufferObject]] : an {{ArrayBuffer}} whose [=Data Block=] is [=identified with=] the above memory address |
| </div> |
| |
| <div algorithm> |
| To <dfn>create a memory buffer</dfn> from a [=memory address=] |memaddr|, perform the following steps: |
| |
| 1. Let |block| be a [=Data Block=] which is [=identified with=] the underlying memory of |memaddr|. |
| 1. Let |buffer| be a new {{ArrayBuffer}} whose \[[ArrayBufferData]] is |block| and \[[ArrayBufferByteLength]] is set to the length of |block|. |
| 1. Set |buffer|.\[[ArrayBufferDetachKey]] to "WebAssembly.Memory". |
| 1. Return |buffer|. |
| </div> |
| |
| <div algorithm> |
| To <dfn>create a memory object</dfn> from a [=memory address=] |memaddr|, perform the following steps: |
| |
| 1. Let |map| be the [=surrounding agent=]'s associated [=Memory object cache=]. |
| 1. If |map|[|memaddr|] [=map/exists=], |
| 1. Return |map|[|memaddr|]. |
| 1. Let |buffer| be a the result of [=create a memory buffer|creating a memory buffer=] from |memaddr|. |
| 1. Let |memory| be a new {{Memory}} instance with \[[Memory]] set to |memaddr| and \[[BufferObject]] set to |buffer|. |
| 1. [=map/Set=] |map|[|memaddr|] to |memory|. |
| 1. Return |memory|. |
| </div> |
| |
| <div algorithm> |
| The <dfn constructor for="Memory">Memory(|descriptor|)</dfn> constructor, when invoked, performs the following steps: |
| 1. let |initial| be |descriptor|["initial"]. |
| 1. If |descriptor|["maximum"] is [=present=], let |maximum| be |descriptor|["maximum"]; otherwise, let |maximum| be empty. |
| 1. If |maximum| is not empty and |maximum| < |initial|, throw a {{RangeError}} exception. |
| 1. Let |memtype| be { min |initial|, max |maximum| } |
| 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. |
| 1. Let (|store|, |memaddr|) be [=mem_alloc=](|store|, |memtype|). If allocation fails, throw a {{RangeError}} exception. |
| 1. Set the [=surrounding agent=]'s [=associated store=] to |store|. |
| 1. [=Create a memory object=] from the memory address |memaddr| and return the result. |
| </div> |
| |
| <div algorithm> |
| To <dfn>reset the Memory buffer</dfn> of |memaddr|, perform the following steps: |
| |
| 1. Let |map| be the [=surrounding agent=]'s associated [=Memory object cache=]. |
| 1. Assert: |map|[|memaddr|] [=map/exists=] |
| 1. Let |memory| be |map|[|memaddr|]. |
| 1. Perform ! [=DetachArrayBuffer=](|memory|.\[[BufferObject]], "WebAssembly.Memory"). |
| 1. Let |buffer| be a the result of [=create a memory buffer|creating a memory buffer=] from |memaddr|. |
| 1. Set |memory|.\[[BufferObject]] to |buffer|. |
| </div> |
| |
| <div algorithm=dom-Memory-grow> |
| The <dfn method for="Memory">grow(|delta|)</dfn> method, when invoked, performs the following steps: |
| 1. Let |memory| be the Memory instance. |
| 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. |
| 1. Let |memaddr| be |memory|.\[[Memory]]. |
| 1. Let |ret| be the [=mem_size=](|store|, |memaddr|). |
| 1. Let |store| be [=mem_grow=](|store|, |memaddr|, |delta|). |
| 1. If |store| is [=error=], throw a {{RangeError}} exception. |
| 1. Set the [=surrounding agent=]'s [=associated store=] to |store|. |
| 1. [=Reset the memory buffer=] of |memaddr|. |
| 1. Return |ret|. |
| </div> |
| |
| Immediately after a WebAssembly [=memory.grow=] instruction executes, perform the following steps: |
| |
| <div algorithm="memory.grow"> |
| 1. If the top of the stack is not [=ππ₯π€.πΌππππ=] (β1), then: |
| 1. Let |frame| be the [=current frame=]. |
| 1. Assert: due to validation, |frame|.[=πππ½ππ
πΎ=].[=ππΎππΊπ½π½ππ=][0] exists. |
| 1. Let |memaddr| be the memory address |frame|.[=πππ½ππ
πΎ=].[=ππΎππΊπ½π½ππ=][0]. |
| 1. [=Reset the memory buffer=] of |memaddr|. |
| </div> |
| |
| <div algorithm> |
| The getter of the <dfn attribute for="Memory">buffer</dfn> attribute of {{Memory}} returns the receiver's \[[BufferObject]] internal slot. |
| </div> |
| |
| <h3 id="tables">Tables</h3> |
| |
| <pre class="idl"> |
| 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; |
| }; |
| </pre> |
| |
| <div> |
| 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: |
| |
| * \[[Table]] : a [=table address=] |
| * \[[Values]] : a List whose elements are either null or [=Exported Function=]s. |
| </div> |
| |
| <div algorithm> |
| To <dfn>create a table object</dfn> from a [=table address=] |tableaddr|, perform the following steps: |
| 1. Let |map| be the [=surrounding agent=]'s associated [=Table object cache=]. |
| 1. If |map|[|tableaddr|] [=map/exists=], |
| 1. Return |map|[|tableaddr|]. |
| 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. |
| 1. Let |values| be a list whose length is [=table_size=](|store|, |tableaddr|) where each element is null. |
| 1. Let |table| be a new {{Table}} instance with \[[Table]] set to |tableaddr| and \[[Values]] set to |values|. |
| 1. [=map/Set=] |map|[|tableaddr|] to |table|. |
| 1. Return |table|. |
| </div> |
| |
| <div algorithm> |
| The <dfn constructor for="Table">Table(|descriptor|)</dfn> constructor, when invoked, performs the following steps: |
| 1. let |initial| be |descriptor|["initial"]. |
| 1. If |descriptor|["maximum"] is [=present=], let |maximum| be |descriptor|["maximum"]; otherwise, let |maximum| be empty. |
| 1. If |maximum| is not empty and |maximum| < |initial|, throw a {{RangeError}} exception. |
| 1. Let |type| be the [=table type=] {[=table type|πππ=] n, [=table type|ππΊπ=] |maximum|} [=table type|πΊπππΏπππΌ=]. |
| 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. |
| 1. Let (|store|, |tableaddr|) be [=table_alloc=](|store|, |type|). <!-- TODO(littledan): Report allocation failure https://github.com/WebAssembly/spec/issues/584 --> |
| 1. Set the [=surrounding agent=]'s [=associated store=] to |store|. |
| 1. [=Create a table object=] from the table address |tableaddr| and return the result. |
| </div> |
| |
| <div algorithm=dom-Table-grow> |
| The <dfn method for="Table">grow(|delta|)</dfn> method, when invoked, performs the following steps: |
| 1. Let |tableaddr| be the Table instance's \[[Table]] internal slot. |
| 1. Let |initialSize| be the length of the Table instance's \[[Values]] internal slot. |
| 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. |
| 1. Let |result| be [=table_grow=](|store|, |tableaddr|, |delta|). |
| 1. If |result| is [=error=], throw a {{RangeError}} exception. |
| |
| Note: The above exception may happen due to either insufficient memory or an invalid size parameter. |
| |
| 1. Set the [=surrounding agent=]'s [=associated store=] to |result|. |
| 1. [=Append=] null to the Table instance's \[[Values]] internal slot |delta| times. |
| 1. Return |initialSize|. |
| </div> |
| |
| <div algorithm> |
| The getter of the <dfn attribute for="Table">length</dfn> attribute of {{Table}} returns the length of the table's \[[Values]] internal slot. |
| </div> |
| |
| <div algorithm> |
| The <dfn method for="Table">get(|index|)</dfn> method, when invoked, performs the following steps: |
| 1. Let |values| be the Table instance's \[[Values]] internal slot. |
| 1. Let |size| be the length of |values|. |
| 1. If |index| ≥ |size|, throw a {{RangeError}} exception. |
| 1. Return |values|[|index|]. |
| </div> |
| |
| <div algorithm> |
| The <dfn method for="Table">set(|index|, |value|)</dfn> method, when invoked, performs the following steps: |
| 1. Let |tableaddr| be the Table instance's \[[Table]] internal slot. |
| 1. Let |values| be the Table instance's \[[Values]] internal slot. |
| 1. If |value| is null, let |funcaddr| be an empty [=function element=]. |
| 1. Otherwise, |
| 1. If |value| does not have a \[[FunctionAddress]] internal slot, throw a {{TypeError}} exception. |
| 1. Let |funcaddr| be |value|.\[[FunctionAddress]]. |
| 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. |
| 1. Let |store| be [=table_write=](|store|, |tableaddr|, |index|, |funcaddr|). |
| 1. If |store| is [=error=], throw a {{RangeError}} exception. |
| 1. Set the [=surrounding agent=]'s [=associated store=] to |store|. |
| 1. Set |values|[|index|] to |value|. |
| 1. Return undefined. |
| </div> |
| |
| <h3 id="globals">Globals</h3> |
| |
| <pre class="idl"> |
| enum ValueType { |
| "i32", |
| "i64", |
| "f32", |
| "f64" |
| }; |
| </pre> |
| |
| Note: this type may be extended with additional cases in future versions of WebAssembly. |
| |
| <pre class="idl"> |
| dictionary GlobalDescriptor { |
| required ValueType value; |
| boolean mutable = false; |
| }; |
| |
| [LegacyNamespace=WebAssembly, Constructor(GlobalDescriptor descriptor, optional any v), Exposed=(Window,Worker,Worklet)] |
| interface Global { |
| any valueOf(); |
| attribute any value; |
| }; |
| </pre> |
| |
| <div> |
| A {{Global}} object represents a single [=global instance=] |
| which can be simultaneously referenced by multiple {{Instance}} objects. Each |
| {{Global}} object has one internal slot: |
| |
| * \[[Global]] : a [=global address=] |
| </div> |
| |
| <div algorithm> |
| To <dfn>create a global object</dfn> from a [=global address=] |globaladdr|, perform the following steps: |
| 1. Let |map| be the current [=agent=]'s associated [=Global object cache=]. |
| 1. If |map|[|globaladdr|] [=map/exists=], |
| 1. Return |map|[|globaladdr|]. |
| 1. Let |global| be a new {{Global}} instance with \[[Global]] set to |globaladdr|. |
| 1. [=map/Set=] |map|[|globaladdr|] to |global|. |
| 1. Return |global|. |
| </div> |
| |
| <div algorithm> |
| The algorithm <dfn>ToValueType</dfn>(|s|) performs the following steps: |
| 1. If |s| equals "i32", return [=ππ₯π€=]. |
| 1. If |s| equals "i64", return [=ππ¨π¦=]. |
| 1. If |s| equals "f32", return [=πΏπ₯π€=]. |
| 1. If |s| equals "f64", return [=πΏπ¨π¦=]. |
| </div> |
| |
| <div algorithm> |
| The algorithm <dfn>DefaultValue</dfn>(|valuetype|) performs the following steps: |
| 1. If |valuetype| equals [=ππ₯π€=], return [=ππ₯π€.πΌππππ=] 0. |
| 1. If |valuetype| equals [=ππ¨π¦=], return [=ππ¨π¦.πΌππππ=] 0. |
| 1. If |valuetype| equals [=πΏπ₯π€=], return [=πΏπ₯π€.πΌππππ=] 0. |
| 1. If |valuetype| equals [=πΏπ¨π¦=], return [=πΏπ¨π¦.πΌππππ=] 0. |
| 1. Assert: This step is not reached. |
| </div> |
| |
| <div algorithm> |
| The <dfn constructor for="Global">Global(|descriptor|, |v|)</dfn> constructor, when invoked, performs the following steps: |
| 1. Let |mutable| be |descriptor|["mutable"]. |
| 1. Let |valuetype| be [=ToValueType=](|descriptor|["value"]). |
| 1. If |v| is undefined, |
| 1. let |value| be [=DefaultValue=](|valuetype|). |
| 1. Otherwise, |
| 1. If |valuetype| is [=ππ¨π¦=], throw a {{TypeError}} exception. |
| 1. Let |value| be [=ToWebAssemblyValue=](|v|, |valuetype|). |
| 1. If |mutable| is true, let |globaltype| be [=var=] |valuetype|; otherwise, let |globaltype| be [=const=] |valuetype|. |
| 1. Let |store| be the current agent's [=associated store=]. |
| 1. Let (|store|, |globaladdr|) be [=global_alloc=](|store|, |globaltype|, |value|). <!-- TODO(littledan): Report allocation failure https://github.com/WebAssembly/spec/issues/584 --> |
| 1. Set the current agent's [=associated store=] to |store|. |
| 1. [=Create a global object=] from the global address |globaladdr| and return the result. |
| </div> |
| |
| <div algorithm> |
| The algorithm <dfn>GetGlobalValue</dfn>({{Global}} |global|) performs the following steps: |
| 1. Let |store| be the current agent's [=associated store=]. |
| 1. Let |globaladdr| be |global|.\[[Global]]. |
| 1. Let |globaltype| be [=global_type=](|store|, |globaladdr|). |
| 1. If |globaltype| is of the form <var ignore>mut</var> [=ππ¨π¦=], throw a {{TypeError}}. |
| 1. Let |value| be [=global_read=](|store|, |globaladdr|). |
| 1. Return [=ToJSValue=](|value|). |
| </div> |
| |
| <div algorithm> |
| The getter of the <dfn attribute for="Global">value</dfn> attribute of {{Global}}, when invoked, performs the following steps: |
| 1. Let |global| be the {{Global}} instance. |
| 1. Return [=GetGlobalValue=](|global|). |
| |
| The setter of the value attribute of {{Global}}, when invoked with a value |v|, performs the following steps: |
| 1. Let |global| be the {{Global}} instance. |
| 1. Let |store| be the current agent's [=associated store=]. |
| 1. Let |globaladdr| be |global|.\[[Global]]. |
| 1. Let |globaltype| be [=global_type=](|store|, |globaladdr|), where |globaltype| is of the form |mut| |valuetype|. |
| 1. If |mut| is [=const=], throw a {{TypeError}}. |
| 1. If |valuetype| is [=ππ¨π¦=], throw a {{TypeError}}. |
| 1. Let |value| be [=ToWebAssemblyValue=](|v|, |valuetype|). |
| 1. Let |store| be [=global_write=](|store|, |globaladdr|, |value|). |
| 1. If |store| is [=error=], throw a {{RangeError}} exception. |
| 1. Set the current agent's [=associated store=] to |store|. |
| </div> |
| |
| <div algorithm> |
| The <dfn method for="Global">valueOf()</dfn> method, when invoked, performs the following steps: |
| 1. Let |global| be the {{Global}} instance. |
| 1. Return [=GetGlobalValue=](|global|). |
| </div> |
| |
| <h3 id="exported-function-exotic-objects">Exported Functions</h3> |
| |
| A WebAssembly function is made available in JavaScript as an <dfn>Exported Function</dfn>. |
| 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=]. |
| |
| <div algorithm> |
| The <dfn>name of the WebAssembly function</dfn> |funcaddr| is found by performing the following steps: |
| |
| 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. |
| 1. Let |funcinst| be |store|.πΏπππΌπ[|funcaddr|]. |
| 1. If |funcinst| is of the form {ππππΎ <var ignore>functype</var>, πππππΌππ½πΎ |hostfunc|}, |
| 1. Assert: |hostfunc| is a JavaScript object and [=IsCallable=](|hostfunc|) is true. |
| 1. Let |index| be the [=index of the host function=] |funcaddr|. |
| 1. Otherwise, |
| 1. Let |moduleinst| be |funcinst|.πππ½ππ
πΎ. |
| 1. Assert: |funcaddr| is contained in |moduleinst|.πΏπππΌπΊπ½π½ππ. |
| 1. Let |index| be the index of |moduleinst|.πΏπππΌπΊπ½π½ππ where |funcaddr| is found. |
| 1. Return ! [=ToString=](|index|). |
| </div> |
| |
| <div algorithm> |
| To create <dfn>a new Exported Function</dfn> from a WebAssembly [=function address=] |funcaddr|, perform the following steps: |
| |
| 1. Let |map| be the [=surrounding agent=]'s associated [=Exported Function cache=]. |
| 1. If |map|[|funcaddr|] [=map/exists=], |
| 1. Return |map|[|funcaddr|]. |
| 1. Let |steps| be "[=call an Exported Function|call the Exported Function=] |funcaddr| with arguments." |
| 1. Let |realm| be the [=current Realm=]. |
| 1. Let |function| be [=CreateBuiltinFunction=](|realm|, |steps|, [=%FunctionPrototype%=], « \[[FunctionAddress]] »). |
| 1. Set |function|.\[[FunctionAddress]] to |funcaddr|. |
| 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. |
| 1. Let |functype| be [=func_type=](|store|, |funcaddr|). |
| 1. Let [|paramTypes|] β [<var ignore>resultTypes</var>] be |functype|. |
| 1. Let |arity| be the length of |paramTypes|. |
| 1. Perform ! [=SetFunctionLength=](|function|, |arity|). |
| 1. Let |name| be the [=name of the WebAssembly function=] |funcaddr|. |
| 1. Perform ! [=SetFunctionName=](|function|, |name|). |
| 1. [=map/Set=] |map|[|funcaddr|] to |function|. |
| 1. Return |function|. |
| </div> |
| |
| <div algorithm> |
| To <dfn>call an Exported Function</dfn> 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=]. |
| 1. Let |functype| be [=func_type=](|store|, |funcaddr|). |
| 1. Let [|parameters|] β [|results|] be |functype|. |
| 1. 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. |
| 1. Let |i| be 0. |
| 1. For each type |t| of |parameters|, |
| 1. If the length of |argValues| > |i|, let |arg| be |argValues|[|i|]. |
| 1. Otherwise, let |arg| be undefined. |
| 1. [=Append=] [=ToWebAssemblyValue=](|arg|, |t|) to |args|. |
| 1. Set |i| to |i| + 1. |
| 1. Let |argsSeq| be a WebAssembly [=sequence=] containing the elements of |args|. |
| 1. Let (|store|, |ret|) be the result of [=func_invoke=](|store|, |funcaddr|, |argsSeq|). |
| 1. Set the [=surrounding agent=]'s [=associated store=] to |store|. |
| 1. If |ret| is [=error=], throw an exception. This exception should be a WebAssembly {{RuntimeError}} exception, unless otherwise indicated by <a href="#errors">the WebAssembly error mapping</a>. |
| 1. If |ret| is empty, return undefined. |
| 1. Otherwise, return [=ToJSValue=](|v|), where |v| is the singular element of |ret|. |
| </div> |
| |
| Note: [=call an Exported Function|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. |
| |
| <div algorithm> |
| To <dfn>run a host function</dfn> from the JavaScript object |func| and type |functype|, perform the following steps: |
| |
| 1. Let [|parameters|] β [|results|] be |functype|. |
| 1. Assert: |results|'s [=list/size=] is at most one. |
| 1. If either |parameters| or |results| contains [=ππ¨π¦=], throw a {{TypeError}}. |
| 1. Let |arguments| be a [=list=] of the arguments of the invocation of this function. |
| 1. Let |jsArguments| be an empty [=list=]. |
| 1. For each |arg| in |arguments|, |
| 1. [=list/Append=] ! [=ToJSValue=](|arg|) to |jsArguments|. |
| 1. Let |ret| be ? [=Call=](|func|, undefined, |jsArguments|). |
| 1. If |results| is [=list/empty=], return undefined. |
| 1. Otherwise, return ? [=ToWebAssemblyValue=](|ret|, |results|[0]). |
| </div> |
| |
| <div algorithm> |
| To <dfn>create a host function</dfn> from the JavaScript object |func| and type |functype|, perform the following steps: |
| |
| 1. Let |hostfunc| be a [=host function=] which performs the following steps when called: |
| 1. Let |result| be the result of [=run a host function|running a host function=] from |func| and |functype|. |
| 1. Assert: |result|.\[[Type]] is throw or return. |
| 1. If |result|.\[[Type]] is [=throw=], then trigger a WebAssembly trap, and propagate |result|.\[[Value]] to the enclosing JavaScript. |
| 1. Otherwise, return |result|.\[[Value]]. |
| 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. |
| 1. Let (|store|, |funcaddr|) be [=func_alloc=](|store|, |functype|, |hostfunc|). |
| 1. Set the [=surrounding agent=]'s [=associated store=] to |store|. |
| 1. Return |funcaddr| |
| </div> |
| |
| <div algorithm> |
| The algorithm <dfn>ToJSValue</dfn>(|w|) coerces a [=WebAssembly value=] to a JavaScript value performs the following steps: |
| |
| 1. Assert: |w| is not of the form [=ππ¨π¦.πΌππππ=] <var ignore>i64</var>. |
| 1. If |w| is of the form [=ππ₯π€.πΌππππ=] |i32|, return [=the Number value=] for [=signed_32=](|i32|). |
| 1. If |w| is of the form [=πΏπ₯π€.πΌππππ=] |f32|, return [=the Number value=] for |f32|. |
| 1. If |w| is of the form [=πΏπ¨π¦.πΌππππ=] |f64|, return [=the Number value=] for |f64|. |
| |
| <!-- If the WebAssembly value is optional, then given `None`, return JavaScript value `undefined`. --> |
| |
| Note: Number values which are equal to NaN may have various observable NaN payloads; see [=NumberToRawBytes=] for details. |
| </div> |
| |
| <div algorithm> |
| The algorithm <dfn>ToWebAssemblyValue</dfn>(|v|, |type|) coerce a JavaScript value to a [=WebAssembly value=] performs the following steps: |
| |
| |
| 1. Assert: |type| is not [=ππ¨π¦=]. |
| 1. If |type| is [=ππ₯π€=], |
| 1. Let |i32| be ? [=ToInt32=](|v|). |
| 1. Return [=ππ₯π€.πΌππππ=] |i32|. |
| 1. 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. |
| 1. Return [=πΏπ₯π€.πΌππππ=] |f32|. |
| 1. If |type| is [=πΏπ¨π¦=], |
| 1. Let |f64| be ? [=ToNumber=](|v|). |
| 1. Return [=πΏπ¨π¦.πΌππππ=] |f64|. |
| |
| </div> |
| |
| <h3 id="error-objects">Error Objects</h3> |
| |
| WebAssembly defines the following Error classes: {{CompileError}}, {{LinkError}}, and {{RuntimeError}}. WebAssembly errors have the following custom bindings: |
| - Unlike normal interface types, the interface prototype object for these exception classes must have as its \[[Prototype]] the intrinsic object [=%ErrorPrototype%=]. |
| - The constructor and properties of WebAssembly errors is as specified for {{NativeError}}. |
| - If an implementation gives native Error objects special powers or nonstandard properties (such as a stack property), it should also expose those on these exception instances. |
| |
| <pre class='idl'> |
| [LegacyNamespace=WebAssembly] |
| interface CompileError { }; |
| |
| [LegacyNamespace=WebAssembly] |
| interface LinkError { }; |
| |
| [LegacyNamespace=WebAssembly] |
| interface RuntimeError { }; |
| </pre> |
| |
| <h2 id="errors">Error Condition Mappings to JavaScript</h2> |
| |
| 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. |
| |
| <h3 id="stack-overflow">Stack Overflow</h3> |
| |
| 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. |
| |
| <h3 id="out-of-memory">Out of Memory</h3> |
| |
| 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. |
| |
| <div class="issue"> |
| A failed allocation of a large table or memory may either result in |
| - a {{RangeError}}, as specified in the {{Memory}} {{Memory/grow()}} and {{Table}} {{Table/grow()}} operations |
| - returning -1 as the [=memory.grow=] instruction |
| - UA-specific OOM behavior as described in this section. |
| In a future revision, we may reconsider more reliable and recoverable errors for allocations of large amounts of memory. |
| |
| See [Issue 879](https://github.com/WebAssembly/spec/issues/879) for further discussion. |
| </div> |
| |
| <h2 id="limits">Implementation-defined Limits</h2> |
| |
| The WebAssembly core specification allows an implementation to define limits on the syntactic structure of the module. |
| While each embedding of WebAssembly may choose to define its own limits, for predictability the standard WebAssembly JavaScript Interface described in this document defines the following exact limits. |
| An implementation must reject a module that exceeds these limits with a {{CompileError}}. |
| In practice, an implementation may run out of resources for valid modules below these limits. |
| |
| <ul> |
| <li>The maximum size of a module is 1073741824 bytes (1 GiB).</li> |
| <li>The maximum number of types defined in the types section is 1000000.</li> |
| <li>The maximum number of functions defined in a module is 1000000.</li> |
| <li>The maximum number of imports declared in a module is 100000.</li> |
| <li>The maximum number of exports declared in a module is 100000.</li> |
| <li>The maximum number of globals defined in a module is 1000000.</li> |
| <li>The maximum number of data segments defined in a module is 100000.</li> |
| |
| <li>The maximum number of tables, including declared or imported tables, is 1.</li> |
| <li>The maximum size of a table is 10000000.</li> |
| <li>The maximum number of table entries in any table initialization is 10000000.</li> |
| <li>The maximum number of memories, including declared or imported memories, is 1.</li> |
| <li>The initial or maximum number of pages for any memory, declared or imported, is at most 32767.</li> |
| |
| <li>The maximum number of parameters to any function is 1000.</li> |
| <li>The maximum number of return values for any function is 1.</li> |
| <li>The maximum size of a function body, including locals declarations, is 7654321 bytes.</li> |
| <li>The maximum number of locals declared in a function, including implicitly declared as parameters, is 50000.</li> |
| |
| </ul> |