-
Notifications
You must be signed in to change notification settings - Fork 35
Support direct global bindings #104
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 13 commits
c6acc6e
88ef520
3ff2891
6013050
aeeba9b
8daa165
19fac54
e639f62
1641b98
6e393ee
fd68140
8ec8b4b
7a122d6
3e70ac4
61e6abd
09b4432
8307913
87df709
447b95d
fa3da3b
19d7635
ef477aa
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -156,6 +156,7 @@ urlPrefix: https://webassembly.github.io/spec/core/; spec: WebAssembly; type: df | |
text: memory address; url: exec/runtime.html#syntax-memaddr | ||
text: global address; url: exec/runtime.html#syntax-globaladdr | ||
text: extern address; url: exec/runtime.html#syntax-externaddr | ||
text: extern subtype; url: valid/types.html#match-externtype | ||
text: page size; url: exec/runtime.html#page-size | ||
url: syntax/types.html#syntax-numtype | ||
text: i32 | ||
|
@@ -1391,6 +1392,8 @@ To <dfn export>parse a WebAssembly module</dfn> given a <a>byte sequence</a> |by | |
1. For each (|moduleName|, <var ignore>name</var>, <var ignore>type</var>) in [=module_imports=](|module|.\[[Module]]), | ||
1. [=set/Append=] |moduleName| to |requestedModules|. | ||
1. Let |moduleRecord| be { | ||
<!-- WebAssembly Module Records --> | ||
\[[Instance]]: ~empty~, | ||
<!-- Abstract Module Records --> | ||
\[[Realm]]: |realm|, | ||
\[[Environment]]: ~empty~, | ||
|
@@ -1470,25 +1473,80 @@ WebAssembly Module Records have the following methods: | |
<h3 id="module-execution">ExecuteModule ( [ |promiseCapability| ] ) Concrete Method</h3> | ||
1. Assert: |promiseCapability| was not provided. | ||
1. Let |record| be this WebAssembly Module Record. | ||
1. Let |module| be |record|.\[[ModuleSource]]. | ||
1. Let |imports| be a new, empty [=map=]. | ||
1. For each (|importedModuleName|, |name|, <var ignore>type</var>) in [=module_imports=](|module|.\[[Module]]), | ||
1. If |imports|[|importedModuleName|] does not exist, set |imports|[|importedModuleName|] to a new, empty [=map=]. | ||
1. Let |module| be |record|.\[[ModuleSource]].\[[Module]]. | ||
1. Let |imports| be « ». | ||
1. [=list/iterate|For each=] (|importedModuleName|, |name|, |importtype|) in [=module_imports=](|module|), | ||
1. Let |importedModule| be [$GetImportedModule$](|record|, |importedModuleName|). | ||
1. Let |value| be ? |importedModule|.\[[Environment]].GetBindingValue(|name|, true). | ||
1. Set |imports|[|importedModuleName|][|name|] to |value|. | ||
1. Let |importObject| be ! [$OrdinaryObjectCreate$](null). | ||
1. For each |key| → |value| of |imports|, | ||
1. Let |moduleImportsObject| be ! [$OrdinaryObjectCreate$](null). | ||
1. For each |importedName| → |importedValue| of |value|, | ||
1. Perform ! [$CreateDataPropertyOrThrow$](|moduleImportsObject|, |importedName|, |importedValue|). | ||
1. Perform ! [$CreateDataPropertyOrThrow$](|importObject|, |key|, |moduleImportsObject|). | ||
1. [=Read the imports=] of |module| with imports |importObject|, and let |imports| be the result. | ||
1. Let |resolution| be |importedModule|.ResolveExport(|name|). | ||
1. If |resolution|.\[[Module]] is a WebAssembly Module Record, | ||
1. Let |resolutionInstance| be |resolution|.\[[Module]].\[[Instance]]. | ||
1. If |resolutionInstance| is ~empty~ then, | ||
1. Throw a {LinkError} exception. | ||
1. Let |resolutionModule| be |resolution|.\[[Module]].\[[ModuleSource]].\[[Module]]. | ||
1. Let |resolutionName| be |resolution|.\[[BindingName]]. | ||
1. Let |externval| be [=instance_export=](|resolutionInstance|, |resolutionName|). | ||
1. Assert: |externval| is not [=error=]. | ||
1. Assert: [=module_exports=](|resolutionModule|) contains an element (|resolutionName|, <var ignore>type</var>). | ||
1. Let |externtype| be the value of |type| for the element (|resolutionName|, |type|) in [=module_exports=](|resolutionModule|). | ||
1. If |importtype| is not an [=extern subtype=] of |externtype|, throw a {{LinkError}} exception. | ||
1. [=list/Append=] |externval| to |imports|. | ||
1. Otherwise, | ||
1. Let |env| be |resolution|.\[[Module]].\[[Environment]]. | ||
1. Let |v| be [=?=] |env|.GetBindingValue(|resolution|.\[[BindingName]], true). | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What if [[BindingName]] is NAMESPACE? e.g. if I import There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We are reading directly from the environment record here, so |
||
1. If |importtype| is of the form [=func=] |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. | ||
1. Otherwise, | ||
1. [=Create a host function=] from |v| and |functype|, and let |funcaddr| be the result. | ||
1. Let <var ignore>index</var> be the number of external functions in |imports|, defining the [=index of the host function=] |funcaddr|. | ||
1. Let |externfunc| be the [=external value=] [=external value|func=] |funcaddr|. | ||
1. [=list/Append=] |externfunc| to |imports|. | ||
1. If |importtype| is of the form [=global=] |mut| |valtype|, | ||
1. Let |store| be the [=surrounding agent=]'s [=associated store=]. | ||
1. If |v| [=implements=] {{Global}}, | ||
1. Let |globaladdr| be |v|.\[[Global]]. | ||
1. Let |targetmut| <var ignore>valuetype</var> be [=global_type=](|store|, |globaladdr|). | ||
1. If |mut| is [=const=] and |targetmut| is [=var=], throw a {{LinkError}} exception. | ||
1. Otherwise, | ||
1. If |valtype| is [=v128=], throw a {{LinkError}} exception. | ||
1. If |mut| is [=var=], throw a {{LinkError}} exception. | ||
1. Let |value| be [=?=] [=ToWebAssemblyValue=](|v|, |valtype|). | ||
1. Let (|store|, |globaladdr|) be [=global_alloc=](|store|, |mut| |valtype|, |value|). | ||
1. Set the [=surrounding agent=]'s [=associated store=] to |store|. | ||
1. Let |externglobal| be [=external value|global=] |globaladdr|. | ||
1. [=list/Append=] |externglobal| to |imports|. | ||
1. If |importtype| is of the form [=mem=] <var ignore>memtype</var>, | ||
1. If |v| does not [=implement=] {{Memory}}, throw a {{LinkError}} exception. | ||
1. Let |externmem| be the [=external value=] [=external value|mem=] |v|.\[[Memory]]. | ||
1. [=list/Append=] |externmem| to |imports|. | ||
1. If |importtype| is of the form [=table=] <var ignore>tabletype</var>, | ||
1. If |v| does not [=implement=] {{Table}}, throw a {{LinkError}} exception. | ||
1. Let |tableaddr| be |v|.\[[Table]]. | ||
1. Let |externtable| be the [=external value=] [=external value|table=] |tableaddr|. | ||
1. [=list/Append=] |externtable| to |imports|. | ||
1. [=Instantiate the core of a WebAssembly module=] |module| with |imports|, and let |instance| be the result. | ||
1. For each |name| in the [=export name list=] of |record|, | ||
1. Perform ! |record|.\[[Environment]].InitializeBinding(|name|, ! Get(|instance|.\[[Exports]], |name|)). | ||
1. Set |record|.\[[Instance]] to |instance|. | ||
1. [=list/iterate|For each=] (|name|, |externtype|) of [=module_exports=](|module|), | ||
1. If |externtype| is of the form [=global=] |mut| |globaltype|, | ||
1. Assert: |externval| is of the form [=external value|global=] |globaladdr|. | ||
1. Let [=external value|global=] |globaladdr| be |externval|. | ||
1. Let |global_value| be [=global_read=](|store|, |globaladdr|). | ||
1. If |globaltype| is not [=v128=], | ||
1. Note: The condition above leaves unsupported JS values as uninitialized in TDZ and therefore as a reference error on | ||
access. When integrating with shared globals, they may be excluded here similarly to v128 above. | ||
Comment on lines
+1551
to
+1552
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do we do this instead of simply not exposing them, making it a linking error? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a great point and thanks for spotting this. The reason is that we need these bindings to work when Wasm modules import other Wasm modules. That is, while these values are not expressible in JS, they should still be exposed as exports to other Wasm. TDZ is therefore a useful way to represent this property. |
||
1. Perform [=!=] |record|.\[[Environment]].InitializeBinding(|name|, [=ToJSValue=](|global_value|)). | ||
1. If |mut| is [=var=], then associate all future mutations of |globaladdr| with the ECMA-262 binding record for |name| in | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fwiw, https://tc39.es/ecma262/#sec-createimportbinding is similarly vague. |
||
|record|.\[[Environment]], such that |record|.\[[Environment]].GetBindingValue(|resolution|.\[[BindingName]], true) | ||
always returns [=ToJSValue=]([=global_read=](|store|, |globaladdr|)) for the current [=surrounding agent=]'s | ||
[=associated store=] |store|. | ||
1. Otherwise, | ||
1. Perform ! |record|.\[[Environment]].InitializeBinding(|name|, ! Get(|instance|.\[[Exports]], |name|)). | ||
|
||
Note: exported bindings are left uninitialized, i.e., in TDZ. | ||
Note: The linking semantics here for Wasm to Wasm modules are identical to the WebAssembly JS API semantics as if passing the | ||
the exports object as the imports object in instantiation. When linking Wasm module imports to JS module exports, the JS API semantics | ||
are exactly followed as well. It is only in the case of importing Wasm from JS that WebAssembly.Global unwrapping is observable on the | ||
WebAssembly Module Record Environment Record. | ||
|
||
</div> | ||
|
||
|
@@ -1500,6 +1558,8 @@ WebAssembly Module Records have the following methods: | |
1. For each (|moduleName|, <var ignore>name</var>, <var ignore>type</var>) in [=module_imports=](|specifier|.\[[Module]]), | ||
1. [=set/Append=] |moduleName| to |requestedModules|. | ||
1. Let |moduleRecord| be { | ||
<!-- WebAssembly Module Records --> | ||
\[[Instance]]: ~empty~, | ||
<!-- Abstract Module Records --> | ||
\[[Realm]]: |realm|, | ||
\[[Environment]]: ~empty~, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(this is confusing, I thought [[Module]] was the Module Record corresponding to [[ModuleSource]] rather than a WebAssembly module, but I don't think we can improve it anyway)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes it's unfortunate we have
[[Module]]
on both a resolve binding record and a WebAssembly.Module module object. Perhaps resolve binding records could refactor at some point to use[[ResolvedModule]]
or something like that to ensure clarity in this kind of scenario.I've split out
resolutionModule
andresolutionName
and also added some assertions to make the relationships clearer.