Skip to content

Commit 4ad0aa2

Browse files
committed
[jsapi] Always queue a task during asynchronous instantiation
JSC will have to do asynchronous compilation work during some instantiations. To be consistent, this PR always queues a task to complete instantiation, except through the synchronous Instance(module) API, to ensure consistency across platforms. This patch also cleans up the specification in various surrounding ways: - Factor out the algorithms for reading imports from the import obj, etc. - Include notes about APIs whose use is discouraged/may be limited
1 parent 4d99845 commit 4ad0aa2

File tree

1 file changed

+79
-45
lines changed

1 file changed

+79
-45
lines changed

document/js-api/index.bs

Lines changed: 79 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -316,10 +316,8 @@ A {{Module}} object represents a single WebAssembly module. Each {{Module}} obje
316316
1. [=Asynchronously compile a WebAssembly module=] from |stableBytes| and return the result.
317317
</div>
318318

319-
<div algorithm="instantiate">
320-
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:
321-
1. Let |module| be |moduleObject|.\[[Module]].
322-
1. If |module|.[=𝗂𝗆𝗉𝗈𝗋𝗍𝗌=] is not an empty list, and |importObject| is undefined, throw a {{TypeError}} exception.
319+
<div algorithm>
320+
To <dfn>read the imports</dfn> from a WebAssembly module |module| from imports object |importObject|, perform the following steps:
323321
1. Let |imports| be an empty [=list=] of [=external value=]s.
324322
1. For each (|moduleName|, |componentName|, |externtype|) in [=module_imports=](|module|), do
325323
1. Let |o| be ? [=Get=](|importObject|, |moduleName|).
@@ -364,59 +362,94 @@ A {{Module}} object represents a single WebAssembly module. Each {{Module}} obje
364362
2. Let |tableaddr| be |v|.\[[Table]]
365363
1. Let |externtable| be the [=external value=] [=external value|𝗍𝖺𝖻𝗅𝖾=] |tableaddr|.
366364
1. [=Append=] |externtable| to |imports|.
367-
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:
365+
1. Return |imports|.
366+
</div>
367+
368+
<div algorithm>
369+
To <dfn>create an instance object</dfn> from a WebAssembly module |module| and instance |instance|, perform the following steps:
370+
1. If |module|.[=𝗂𝗆𝗉𝗈𝗋𝗍𝗌=] is not an empty list, and |importObject| is undefined, throw a {{TypeError}} exception.
371+
1. Let |exportsObject| be ! [=ObjectCreate=](null).
372+
1. For each pair (|name|, |externtype|) in [=module_exports=](|module|),
373+
1. Let |externval| be [=get_export=](|instance|, |name|).
374+
1. Assert: |externval| is not [=error=].
375+
1. If |externtype| is of the form [=𝖿𝗎𝗇𝖼=] |functype|,
376+
1. Assert: |externval| is of the form [=external value|𝖿𝗎𝗇𝖼=] |funcaddr|.
377+
1. Let [=external value|𝖿𝗎𝗇𝖼=] |funcaddr| be |externval|.
378+
1. Let |func| be the result of creating [=a new Exported Function=] from |funcaddr|.
379+
1. Let |value| be |func|.
380+
1. If |externtype| is of the form [=𝗀𝗅𝗈𝖻𝖺𝗅=] <var ignore>globaltype</var>,
381+
1. Assert: |externval| is of the form [=external value|𝗀𝗅𝗈𝖻𝖺𝗅=] |globaladdr|.
382+
1. Let [=external value|𝗀𝗅𝗈𝖻𝖺𝗅=] |globaladdr| be |externval|.
383+
1. Let |global| be [=create a global object|a new Global object=] created from |globaladdr|.
384+
1. Let |value| be |global|.
385+
1. If |externtype| is of the form [=𝗆𝖾𝗆=] |memtype|,
386+
1. Assert: |externval| is of the form [=external value|𝗆𝖾𝗆=] |memaddr|.
387+
1. Let [=external value|𝗆𝖾𝗆=] |memaddr| be |externval|.
388+
1. Let |memory| be [=create a memory object|a new Memory object=] created from |memaddr|.
389+
1. Let |value| be |memory|.
390+
1. Otherwise, |externtype| is of the form [=𝗍𝖺𝖻𝗅𝖾=] |tabletype|,
391+
1. Assert: |externval| is of the form [=external value|𝗍𝖺𝖻𝗅𝖾=] |tableaddr|.
392+
1. Let [=external value|𝗍𝖺𝖻𝗅𝖾=] |tableaddr| be |externval|.
393+
1. Let |table| be [=create a Table object|a new Table object=] created from |tableaddr|.
394+
1. Let |value| be |table|.
395+
1. Let |status| be ! [=CreateDataProperty=](|exportsObject|, |name|, |value|).
396+
1. Assert: |status| is true.
397+
398+
Note: the validity and uniqueness checks performed during [=WebAssembly module validation=] ensure that each property name is valid and no properties are defined twice.
399+
1. Perform ! [=SetIntegrityLevel=](|exportsObject|, `"frozen"`).
400+
1. Return a new {{Instance}} object whose internal \[[Instance]] slot is set to |instance| and the \[[Exports]] slot to |exportsObject|.
401+
</div>
402+
403+
<div algorithm>
404+
To <dfn>instantate the core of a WebAssembly module</dfn> from a module |module| and imports |imports|, perform the following steps:
405+
406+
1. Let |store| be the [=surrounding agent=]'s [=associated store=].
368407
1. Let (|store|, |instance|) be [=instantiate_module=](|store|, |module|, |imports|).
369408
1. If |instance| is [=error=], throw an appropriate exception type:
370409
* A {{LinkError}} exception for most cases which occur during linking.
371410
* 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.
372411
* Another error type if appropriate, for example an out-of-memory exception, as documented in <a href="#errors">the WebAssembly error mapping</a>.
373-
1. Let |exportsObject| be ! [=ObjectCreate=](null).
374-
1. For each pair (|name|, |externtype|) in [=module_exports=](|module|),
375-
1. Let |externval| be [=get_export=](|instance|, |name|).
376-
1. Assert: |externval| is not [=error=].
377-
1. If |externtype| is of the form [=𝖿𝗎𝗇𝖼=] |functype|,
378-
1. Assert: |externval| is of the form [=external value|𝖿𝗎𝗇𝖼=] |funcaddr|.
379-
1. Let [=external value|𝖿𝗎𝗇𝖼=] |funcaddr| be |externval|.
380-
1. Let |func| be the result of creating [=a new Exported Function=] from |funcaddr|.
381-
1. Let |value| be |func|.
382-
1. If |externtype| is of the form [=𝗀𝗅𝗈𝖻𝖺𝗅=] <var ignore>globaltype</var>,
383-
1. Assert: |externval| is of the form [=external value|𝗀𝗅𝗈𝖻𝖺𝗅=] |globaladdr|.
384-
1. Let [=external value|𝗀𝗅𝗈𝖻𝖺𝗅=] |globaladdr| be |externval|.
385-
1. Let |global| be [=create a global object|a new Global object=] created from |globaladdr|.
386-
1. Let |value| be |global|.
387-
1. If |externtype| is of the form [=𝗆𝖾𝗆=] |memtype|,
388-
1. Assert: |externval| is of the form [=external value|𝗆𝖾𝗆=] |memaddr|.
389-
1. Let [=external value|𝗆𝖾𝗆=] |memaddr| be |externval|.
390-
1. Let |memory| be [=create a memory object|a new Memory object=] created from |memaddr|.
391-
1. Let |value| be |memory|.
392-
1. Otherwise, |externtype| is of the form [=𝗍𝖺𝖻𝗅𝖾=] |tabletype|,
393-
1. Assert: |externval| is of the form [=external value|𝗍𝖺𝖻𝗅𝖾=] |tableaddr|.
394-
1. Let [=external value|𝗍𝖺𝖻𝗅𝖾=] |tableaddr| be |externval|.
395-
1. Let |table| be [=create a Table object|a new Table object=] created from |tableaddr|.
396-
1. Let |value| be |table|.
397-
1. Let |status| be ! [=CreateDataProperty=](|exportsObject|, |name|, |value|).
398-
1. Assert: |status| is true.
399-
400-
Note: the validity and uniqueness checks performed during [=WebAssembly module validation=] ensure that each property name is valid and no properties are defined twice.
401-
1. Perform ! [=SetIntegrityLevel=](|exportsObject|, `"frozen"`).
402-
1. Let |instanceObject| be a new {{Instance}} object whose internal \[[Instance]] slot is set to |instance| and the \[[Exports]] slot to |exportsObject|.
403-
1. If |steps| is provided, perform |steps| given |instanceObject|.
404-
1. Otherwise, return |instanceObject|.
412+
1. Set the [=surrounding agent=]'s [=associated store=] to |store|.
413+
1. Return |instance|.
414+
</div>
415+
416+
<div algorithm="instantiate">
417+
To <dfn>asynchronously instantiate a WebAssembly module</dfn> from a {{Module}} |moduleObject| and imports |importObject|, perform the following steps:
418+
1. Let |module| be |moduleObject|.\[[Module]].
419+
1. Let |promise| be [=a new promise=].
420+
1. [=Read the imports=] of |module| with imports |importObject|, and let |imports| be the result. If this operation throws an exception, catch it, [=reject=]
421+
1. Run the following steps [=in parallel=]:
422+
Note: Implementation-specific work may be performed here.
423+
1. [=Queue a task=] to perform the following steps:
424+
1. [=Instantiate the core of a WebAssembly module=] |module| with |imports|, and let |instance| be the result. If this operation throws an exception, catch it, [=reject=] |promise| with the exception, and return |promise|.
425+
1. [=Create an instance object=] from |module| and |instance|, and let the result be |instanceObject|. If this operation throws an exception, catch it, [=reject=] |promise| with the exception, and return |promise|.
426+
1. [=Resolve=] |promise| with |instance|.
427+
1. Return |promise|.
428+
</div>
429+
430+
<div algorithm="instantiate">
431+
To <dfn>synchronously instantiate a WebAssembly module</dfn> from a {{Module}} |moduleObject| and imports |importObject|, perform the following steps:
432+
1. Let |module| be |moduleObject|.\[[Module]].
433+
1. [=Read the imports=] of |module| with imports |importObject|, and let |imports| be the result.
434+
1. [=Instantiate the core of a WebAssembly module=] |module| with |imports|, and let |instance| be the result.
435+
1. [=Create an instance object=] from |module| and |instance|, and let the result be |instanceObject|.
436+
1. Return |instanceObject|.
405437
</div>
406438

407439
<div algorithm>
408440
To <dfn>instantiate a promise of a module</dfn> |promiseOfModule| with imports |importObject|, perform the following steps:
409441

410442
1. Let |promise| be [=a new promise=]
411443
1. [=Upon fulfillment=] of |promiseOfModule| with value |module|:
412-
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.
444+
1. [=asynchronously instantiate a WebAssembly module|Instantiate the WebAssembly module=] |module| importing |importObject|, and let |innerPromise| be the result.
445+
1. [=Upon fulfillment=] of |innerPromise| with value |instance|.
413446
1. Let |result| be a {{WebAssemblyInstantiatedSource}} dictionary with {{WebAssemblyInstantiatedSource/module}} set to |module| and {{WebAssemblyInstantiatedSource/instance}} set to |instance|.
414447
1. [=Resolve=] |promise| with |result|.
448+
1. [=Upon rejection=] of |innerPromise| with reason |reason|:
449+
1. [=Reject=] |promise| with |reason|.
415450
1. [=Upon rejection=] of |promiseOfModule| with reason |reason|:
416451
1. [=Reject=] |promise| with |reason|.
417452
1. Return |promise|.
418-
419-
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.
420453
</div>
421454

422455
<div algorithm>
@@ -428,10 +461,7 @@ A {{Module}} object represents a single WebAssembly module. Each {{Module}} obje
428461

429462
<div algorithm>
430463
The <dfn method for="WebAssembly">instantiate(|moduleObject|, |importObject|)</dfn> method, when invoked, performs the following steps:
431-
1. Let |promise| be [=a new promise=].
432-
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.
433-
1. [=Resolve=] |promise| with |instance|.
434-
1. Return |promise|
464+
1. [=asynchronously instantiate a WebAssembly module|Asynchronously instantiate the WebAssembly module=] |moduleObject| importing |importObject|, and return the result.
435465
</div>
436466

437467
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>.
@@ -515,6 +545,8 @@ interface Module {
515545
1. [=Compile a WebAssembly module|Compile the WebAssembly module=] |stableBytes| and store the result as |module|.
516546
1. If |module| is [=error=], throw a {{CompileError}} exception.
517547
1. [=Construct a WebAssembly module object=] from |module| and |stableBytes|, and return the result.
548+
549+
Note: Some implementations may enforce a size limitation on |bytes|. Use of this API is discouraged, in favor of asynchronous APIs.
518550
</div>
519551

520552
<h3 id="instances">Instances</h3>
@@ -527,7 +559,9 @@ interface Instance {
527559
</pre>
528560

529561
<div algorithm>
530-
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.
562+
The <dfn constructor for="Instance">Instance(|module|, |importObject|)</dfn> constructor, when invoked, [=synchronously instantiate a WebAssembly module|synchronously instantiates the WebAssembly module=] |module| importing |importObject| and returns the result.
563+
564+
Note: The use of this synchronous API is discouraged, as some implementations sometimes do long-running compilation work when instantiating.
531565
</div>
532566

533567
<div algorithm>

0 commit comments

Comments
 (0)