-
Notifications
You must be signed in to change notification settings - Fork 40
Changes from all commits
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 |
---|---|---|
|
@@ -100,6 +100,9 @@ urlPrefix: https://webassembly.github.io/spec/core/; spec: WebAssembly; type: df | |
text: 𝗂𝟥𝟤.𝖼𝗈𝗇𝗌𝗍 | ||
text: 𝖿𝟥𝟤.𝖼𝗈𝗇𝗌𝗍 | ||
text: 𝖿𝟨𝟦.𝖼𝗈𝗇𝗌𝗍 | ||
text: ref.null | ||
text: ref.func | ||
text: ref.host | ||
text: function index; url: syntax/modules.html#syntax-funcidx | ||
text: function instance; url: exec/runtime.html#function-instances | ||
text: init_store; url: appendix/embedding.html#embed-init-store | ||
|
@@ -132,11 +135,16 @@ urlPrefix: https://webassembly.github.io/spec/core/; spec: WebAssembly; type: df | |
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 | ||
url: syntax/types.html#syntax-valtype | ||
text: host address; url: exec/runtime.html#syntax-hostaddr | ||
url: syntax/types.html#syntax-numtype | ||
text: 𝗂𝟥𝟤 | ||
text: 𝗂𝟨𝟦 | ||
text: 𝖿𝟥𝟤 | ||
text: 𝖿𝟨𝟦 | ||
url: syntax/types.html#syntax-reftype | ||
text: anyref | ||
text: anyeqref | ||
text: anyfunc | ||
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 | ||
|
@@ -223,6 +231,7 @@ 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>Host value cache</dfn>, mapping [=host address=]es to values. | ||
|
||
<h2 id="webassembly-namespace">The WebAssembly Namespace</h2> | ||
|
||
|
@@ -326,7 +335,7 @@ A {{Module}} object represents a single WebAssembly module. Each {{Module}} obje | |
1. [=Append=] |externfunc| to |imports|. | ||
1. If |externtype| is of the form [=𝗀𝗅𝗈𝖻𝖺𝗅=] |globaltype|, | ||
1. If |globaltype| is [=𝗂𝟨𝟦=] or [=Type=](|v|) is not [=Number=], throw a {{LinkError}} exception. | ||
1. Let |value| be [=ToWebAssemblyValue=](|v|, |globaltype|.<em>[=global type|valtype=]</em>) | ||
1. Let |value| be [=ToWebAssemblyValue=](|v|, |globaltype|.<em>[=global type|valtype=]</em>, {{LinkError}}) | ||
1. Assert: |globaltype|.<em>[=global type|mut=]</em> is [=global type|𝖼𝗈𝗇𝗌𝗍=], as verified by WebAssembly validation. | ||
1. Let |store| be the [=surrounding agent=]'s [=associated store=]. | ||
1. Let (|store|, |globaladdr|) be [=alloc_global=](|store|, |globaltype|, |value|). | ||
|
@@ -590,6 +599,8 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each | |
|
||
<pre class="idl"> | ||
enum TableKind { | ||
"anyref", | ||
"anyeqref", | ||
"anyfunc", | ||
// Note: More values may be added in future iterations, | ||
// e.g., typed function references, typed GC references | ||
|
@@ -742,7 +753,7 @@ This slot holds a [=function address=] relative to the [=surrounding agent=]'s [ | |
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. [=Append=] [=ToWebAssemblyValue=](|arg|, |t|, {{TypeError}}) to |args|. | ||
1. Set |i| to |i| + 1. | ||
1. Let (|store|, |ret|) be the result of [=invoke_func=](|store|, |funcaddr|, |args|). | ||
1. Set the [=surrounding agent=]'s [=associated store=] to |store|. | ||
|
@@ -767,7 +778,7 @@ Note: Exported Functions do not have a \[[Construct]] method and thus it is not | |
1. Let |ret| be ? [=Call=](|func|, undefined, |jsArguments|). If an exception is thrown, trigger a WebAssembly trap, and propagate the exception to the enclosing JavaScript. | ||
1. Let [|parameters|] → [|results|] be |functype|. | ||
1. If |results| is empty, return undefined. | ||
1. Otherwise, return [=ToWebAssemblyValue=](|ret|, |results|[0]). | ||
1. Otherwise, return [=ToWebAssemblyValue=](|ret|, |results|[0], {{TypeError}}). | ||
1. Let |store| be the [=surrounding agent=]'s [=associated store=]. | ||
1. Let (|store|, |funcaddr|) be [=alloc_func=](|store|, |functype|, |hostfunc|). | ||
1. Set the [=surrounding agent=]'s [=associated store=] to |store|. | ||
|
@@ -781,14 +792,24 @@ Assert: |w| is not of the form [=𝗂𝟨𝟦.𝖼𝗈𝗇𝗌𝗍=] |i64|. | |
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|. | ||
1. If |w| is of the form [=ref.null=], return null. | ||
1. If |w| is of the form [=ref.func=] |funcaddr|, return the result of creating [=a new Exported Function=] from |funcaddr|. | ||
1. If |w| is of the form [=ref.host=] |hostaddr|, return the result of [=retrieving a host value=] from |hostaddr|. | ||
|
||
<!-- If the WebAssembly value is optional, then given `None`, return JavaScript value `undefined`. --> | ||
|
||
Note: Implementations may optionally replace the NaN payload with any other NaN payload at this point in the f32 or f64 cases; such a change would not be observable through [=NumberToRawBytes=]. | ||
</div> | ||
|
||
<div algorithm> | ||
The algorithm <dfn>ToWebAssemblyValue</dfn>(|v|, |type|) coerce a JavaScript value to a [=WebAssembly value=] performs the following steps: | ||
For <dfn>retrieving a host value</dfn> from a [=host address=] |hostaddr|, perform the following steps: | ||
1. Let |map| be the [=surrounding agent=]'s associated [=host value cache=]. | ||
1. Assert: |map|[|hostaddr|] [=map/exists=]. | ||
1. Return |map|[|hostaddr|]. | ||
</div> | ||
|
||
<div algorithm> | ||
The algorithm <dfn>ToWebAssemblyValue</dfn>(|v|, |type|, |error|) coerces a JavaScript value to a [=WebAssembly value=] performs the following steps: | ||
|
||
|
||
Assert: |type| is not [=𝗂𝟨𝟦=]. | ||
|
@@ -801,9 +822,34 @@ Assert: |type| is not [=𝗂𝟨𝟦=]. | |
1. If |type| is [=𝖿𝟨𝟦=], | ||
1. Let |f64| be ? [=ToNumber=](|v|). | ||
1. Return [=𝖿𝟨𝟦.𝖼𝗈𝗇𝗌𝗍=] |f64|. | ||
1. If |type| is [=anyref=], | ||
1. If |v| is a primitive value but not a string, symbol, or null, throw |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. What's the criteria for allowing Strings here (which I think get implicitly boxed), while primitive number/boolean are disallowed although they could also be implicitly boxed? 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. Excellent question, which has also been asked by @gahaas. I believe it would be rather useful to allow any JS value here, but @lukewagner mentioned some reasons why that might be difficult in SpiderMonkey. I have it on my slides as an open question for this week's meeting. 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. Well, my expectation here is that string promitives wouldn't autobox into String objects. So, e.g., the identity function would preserve primitive-ness. 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. The problem is the implementation of ref.eq. As far as I understand it, non-primitive JS objects have an identity, so we can implement ref.eq by comparing the references to two JS objects, instead of doing a deep comparison. Primitive values, however, don't have an identity. The same number, or the same string, may be stored multiple times on the heap, in different representations. Therefore we would have to do a deep comparison for primitive values, or we would have to canonicalize primitive values in ToWebAssemblyValue to allow a reference comparison again. 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. @gahaas, ref.eq requires @lukewagner, why would other primitive types require autoboxing either? I think you can treat any tagged pointer as a reference without problem. 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. @rossberg To make sure I understand: are you talking about being able to stick, e.g., a bool into an 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. @lukewagner, yes, there is no technical reason AFAICS why we cannot allow that. Simply view all JS values as reference types. Some of them may be unboxed/flattened in practice, but that is an implementation detail that we can leave entirely transparent to Wasm, because it can never tell the difference. Intrefs will certainly be in a similar category, but here the motivation is (a) simplicity, and (b) completeness. I think you want all JS value to be able to round-trip through Wasm without having to distinguish them. That makes it much easier to implement generic JS data structures in Wasm. 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. I certainly see the value of round-tripping any JS value (and |
||
1. Return the result of [=allocating a host address=] for |v|. | ||
1. If |type| is [=anyeqref=], | ||
1. If |v| is a primitive value but not a symbol or null, throw |error|. | ||
1. Return the result of [=allocating a host address=] for |v|. | ||
1. If |type| is [=anyfunc=], | ||
1. If |v| is not an [=Exported function=] or null, throw |error|. | ||
1. Return the result of [=allocating a host address=] for |v|. | ||
|
||
</div> | ||
|
||
<div algorithm> | ||
For <dfn>allocating a host address</dfn> for a value |v|, perform the following steps: | ||
1. If |v| is null, | ||
1. Return [=ref.null=]. | ||
1. If |v| is an [=Exported Function=], | ||
1. Let |funcaddr| be the value of |v|'s \[[FunctionAddress]] internal slot. | ||
1. Return [=ref.func=] |funcaddr|. | ||
1. Let |map| be the [=surrounding agent=]'s associated [=host value cache=]. | ||
1. If a [=host address=] |hostaddr| exists such that |map|[|hostaddr|] is the same as |v|, | ||
1. Return [=ref.host=] |hostaddr|. | ||
1. Let [=host address=] |hostaddr| be the smallest address such that |map|[|hostaddr|] [=map/exists=] is false. | ||
1. [=map/Set=] |map|[|hostaddr|] to |v|. | ||
1. Return [=ref.host=] |hostaddr|. | ||
</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: | ||
|
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.
Just checking my understanding here: this will not create a new function each time ToWebAssemblyValue is called, because the Exported Function creation early returns if it's been already created before? (i.e. exported function creation is a projection)
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.
What is the
functype
of such an Exported Function? A new kind of signatureanysig
that validates every static signature check but requires a dynamic signature check instead?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, exported functions are cached and no funcaddr will be wrapped more than once. The type is determined by the function instance it points to.