From 3f2e9f1216d2e274554490eb79775458559abdb8 Mon Sep 17 00:00:00 2001 From: Daniel Ehrenberg Date: Wed, 7 Mar 2018 19:10:34 +0100 Subject: [PATCH] Normative: Permit work in parallel during instantiation 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 #741 See also https://github.com/webpack/webpack/issues/6433 --- document/js-api/index.bs | 87 ++++++++++++++++++++-------------------- 1 file changed, 44 insertions(+), 43 deletions(-) diff --git a/document/js-api/index.bs b/document/js-api/index.bs index 19d19808fd..eae6df7ba5 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -305,7 +305,7 @@ A {{Module}} object represents a single WebAssembly module. Each {{Module}} obje
- To instantiate a WebAssembly module from a {{Module}} |moduleObject| and imports |importObject|, perform the following steps: + To instantiate a WebAssembly module 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. @@ -348,43 +348,45 @@ 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 the WebAssembly error mapping. - 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 [=π—€π—…π—ˆπ–»π–Ίπ—…=] |globaltype|, - 1. If |globaltype|.[=global type|valtype=]) is [=π—‚πŸ¨πŸ¦=], throw a {{LinkError}} exception. - 1. Assert: |globaltype|.[=global type|mut=] is [=global type|π–Όπ—ˆπ—‡π—Œπ—=], as verified by WebAssembly validation. - 1. Assert: |externval| is of the form [=external value|π—€π—…π—ˆπ–»π–Ίπ—…=] |globaladdr|. - 1. Let [=external value|π—€π—…π—ˆπ–»π–Ίπ—…=] |globaladdr| be |externval|. - 1. Let |value| be [=ToJSValue=]([=read_global=](|store|, |globaladdr|)). - 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 the WebAssembly error mapping. + 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 [=π—€π—…π—ˆπ–»π–Ίπ—…=] |globaltype|, + 1. If |globaltype|.[=global type|valtype=]) is [=π—‚πŸ¨πŸ¦=], throw a {{LinkError}} exception. + 1. Assert: |globaltype|.[=global type|mut=] is [=global type|π–Όπ—ˆπ—‡π—Œπ—=], as verified by WebAssembly validation. + 1. Assert: |externval| is of the form [=external value|π—€π—…π—ˆπ–»π–Ίπ—…=] |globaladdr|. + 1. Let [=external value|π—€π—…π—ˆπ–»π–Ίπ—…=] |globaladdr| be |externval|. + 1. Let |value| be [=ToJSValue=]([=read_global=](|store|, |globaladdr|)). + 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|.
@@ -392,9 +394,9 @@ A {{Module}} object represents a single WebAssembly module. Each {{Module}} obje 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|. @@ -413,8 +415,7 @@ A {{Module}} object represents a single WebAssembly module. Each {{Module}} obje
The instantiate(moduleObject, importObject) 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=] |module| 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=] |module| 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|