Skip to content

Commit

Permalink
Normative: Permit work in parallel during instantiation
Browse files Browse the repository at this point in the history
On JSC, some compilation work takes place the first time that a
Module is instantiated. If the module is instantiated in an
asynchronous way, the work happens off the main thread. This patch
loosens the specification of WebAssembly module instantiation
to permit this specific type of delay.

Based on skimming the code (but not running tests), I believe that
the new specification matches 3/4 of the implementations I examined.
The one which might not fit is V8, which defers reading properties
of the import object to a microtask queue item at the beginning
of WebAssembly.instantiate(Module), unlike the others, which read it
synchronously.

The previous specification didn't match any implementations, as it
specified to queue an HTML task at the beginning of the
WebAssembly.instantiate(Module) method, which no implementation
actually did to my knowledge. Punting to a queue there doesn't really
serve any purpose and was simply an error in drafting the previous
specification.

Closes WebAssembly#741
See also webpack/webpack#6433
  • Loading branch information
littledan committed Sep 7, 2018
1 parent 4ccad09 commit b8ea19a
Showing 1 changed file with 43 additions and 42 deletions.
85 changes: 43 additions & 42 deletions document/js-api/index.bs
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ A {{Module}} object represents a single WebAssembly module. Each {{Module}} obje
</div>

<div algorithm="instantiate">
To <dfn>instantiate a WebAssembly module</dfn> from a {{Module}} |moduleObject| and imports |importObject|, perform the following steps:
To <dfn>instantiate a WebAssembly module</dfn> from a {{Module}} |moduleObject| and imports |importObject|, and optional algorithm |steps| is given |importObject| as a parameter, perform the following steps:
1. Let |module| be |moduleObject|.\[[Module]].
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.
Expand Down Expand Up @@ -362,52 +362,54 @@ A {{Module}} object represents a single WebAssembly module. Each {{Module}} obje
2. Let |tableaddr| be |v|.\[[Table]]
1. Let |externtable| be the [=external value=] [=external value|𝗍𝖺𝖻𝗅𝖾=] |tableaddr|.
1. [=Append=] |externtable| to |imports|.
1. Let (|store|, |instance|) be [=instantiate_module=](|store|, |module|, |imports|).
1. 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 <a href="#errors">the WebAssembly error mapping</a>.
1. Let |exportsObject| be ! [=ObjectCreate=](null).
1. For each pair (|name|, |externtype|) in [=module_exports=](|module|),
1. Let |externval| be [=get_export=](|instance|, |name|).
1. Assert: |externval| is not [=error=].
1. If |externtype| is of the form [=𝖿𝗎𝗇𝖼=] |functype|,
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 [=𝗆𝖾𝗆=] |memtype|,
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 [=𝗍𝖺𝖻𝗅𝖾=] |tabletype|,
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. Let |instanceObject| be a new {{Instance}} object whose internal \[[Instance]] slot is set to |instance| and the \[[Exports]] slot to |exportsObject|.
1. Return |instanceObject|.
1. If |steps| is provided, user agents may either perform the following steps, or may perform additional work [=in parallel=] and then [=queue a task=] to perform the following steps. If |steps| is not provided, perform the following steps:
1. Let (|store|, |instance|) be [=instantiate_module=](|store|, |module|, |imports|).
1. 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 <a href="#errors">the WebAssembly error mapping</a>.
1. Let |exportsObject| be ! [=ObjectCreate=](null).
1. For each pair (|name|, |externtype|) in [=module_exports=](|module|),
1. Let |externval| be [=get_export=](|instance|, |name|).
1. Assert: |externval| is not [=error=].
1. If |externtype| is of the form [=𝖿𝗎𝗇𝖼=] |functype|,
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 [=𝗆𝖾𝗆=] |memtype|,
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 [=𝗍𝖺𝖻𝗅𝖾=] |tabletype|,
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. Let |instanceObject| be a new {{Instance}} object whose internal \[[Instance]] slot is set to |instance| and the \[[Exports]] slot to |exportsObject|.
1. If |steps| is provided, perform |steps| given |instanceObject|.
1. Otherwise, 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. [=instantiate a WebAssembly module|Instantiate the WebAssembly module=] |module| importing |importObject|, with the following steps given |instance|. 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|.
Expand All @@ -425,8 +427,7 @@ A {{Module}} object represents a single WebAssembly module. Each {{Module}} obje
<div algorithm>
The <dfn method for="WebAssembly">instantiate(|moduleObject|, |importObject|)</dfn> method, when invoked, performs the following steps:
1. Let |promise| be [=a new promise=].
1. [=Queue a task=] to perform the following steps:
1. [=instantiate a WebAssembly module|Instantiate the WebAssembly module=] |moduleObject| importing |importObject|, and let |instance| be the result. If this throws an exception, catch it, and [=reject=] |promise| with the exception.
1. [=instantiate a WebAssembly module|Instantiate the WebAssembly module=] |moduleObject| importing |importObject|, with the following steps, given |instance|. If this throws an exception, catch it, and [=reject=] |promise| with the exception.
1. [=Resolve=] |promise| with |instance|.
1. Return |promise|
</div>
Expand Down

0 comments on commit b8ea19a

Please sign in to comment.