Skip to content

Commit 4480daf

Browse files
rvolosatovslukewagner
authored andcommitted
formalize component value definitions
Signed-off-by: Roman Volosatovs <[email protected]>
1 parent c464bbb commit 4480daf

File tree

2 files changed

+233
-17
lines changed

2 files changed

+233
-17
lines changed

design/mvp/Binary.md

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ section ::= section_0(<core:custom>) => ϵ
3636
| s: section_9(<start>) => [s]
3737
| i*:section_10(vec(<import>)) => i*
3838
| e*:section_11(vec(<export>)) => e*
39+
| v*:section_12(vec(<value>)) => v* 🪙
3940
```
4041
Notes:
4142
* Reused Core binary rules: [`core:section`], [`core:custom`], [`core:module`]
@@ -215,12 +216,14 @@ importdecl ::= in:<importname'> ed:<externdesc> => (import in ed)
215216
exportdecl ::= en:<exportname'> ed:<externdesc> => (export en ed)
216217
externdesc ::= 0x00 0x11 i:<core:typeidx> => (core module (type i))
217218
| 0x01 i:<typeidx> => (func (type i))
218-
| 0x02 t:<valtype> => (value t) 🪙
219+
| 0x02 b:<valuebound> => (value b) 🪙
219220
| 0x03 b:<typebound> => (type b)
220221
| 0x04 i:<typeidx> => (component (type i))
221222
| 0x05 i:<typeidx> => (instance (type i))
222223
typebound ::= 0x00 i:<typeidx> => (eq i)
223224
| 0x01 => (sub resource)
225+
valuebound ::= 0x00 i:<valueidx> => (eq i) 🪙
226+
| 0x01 t:<valtype> => t 🪙
224227
```
225228
Notes:
226229
* The type opcodes follow the same negative-SLEB128 scheme as Core WebAssembly,
@@ -347,6 +350,64 @@ Notes:
347350
* `<integrity-metadata>` is as defined by the
348351
[SRI](https://www.w3.org/TR/SRI/#dfn-integrity-metadata) spec.
349352

353+
## 🪙 Value Definitions
354+
355+
(See [Value Definitions](Explainer.md#value-definitions) in the explainer.)
356+
357+
```ebnf
358+
value ::= t:<valtype> v:<val(t)> => (value t v)
359+
val(bool) ::= 0x00 => false
360+
| 0x01 => true
361+
val(u8) ::= v:<core:u8> => v
362+
val(s8) ::= v:<core:s8> => v
363+
val(s16) ::= v:<core:s16> => v
364+
val(u16) ::= v:<core:u16> => v
365+
val(s32) ::= v:<core:s32> => v
366+
val(u32) ::= v:<core:u32> => v
367+
val(s64) ::= v:<core:s64> => v
368+
val(u64) ::= v:<core:u64> => v
369+
val(f32) ::= v:<core:f32> => v (if !isnan(v))
370+
| 0x00 0x00 0xC0 0x7F => nan
371+
val(f64) ::= v:<core:f64> => v (if !isnan(v))
372+
| 0x00 0x00 0x00 0x00 0x00 0x00 0xF8 0x7F => nan
373+
val(char) ::= v:<core:u32> => v (if v < 0xD800 or 0xE000 <= v <= 0x10FFFF)
374+
val(string) ::= v:<core:name> => v
375+
val(i:<typeidx>) ::= v:<val(type-index-space[i])> => v
376+
val((record (field l t)+)) ::= v+:<val(t)>+ => (record v+)
377+
val((variant (case l t?)+) ::= i:<core:u32> v?:<val(t[i])>? => (variant l[i] v?)
378+
val((list t)) ::= v:vec(<val(t)>) => (list v)
379+
val((tuple t+)) ::= v+:<val(t)>+ => (tuple v+)
380+
val((flags l+)) ::= v:<core:uN> => (flags (l[i] for i in 0..N-1 if v & 2^i > 0)) (where N = |l+|)
381+
val((enum l+)) ::= i:<core:u32> => (enum l[i])
382+
val((option t)) ::= 0x00 => none
383+
| 0x01 v:<val(t)> => (some v)
384+
val((result)) ::= 0x00 => ok
385+
| 0x01 => error
386+
val((result t)) ::= 0x00 v:<val(t)> => (ok v)
387+
| 0x01 => error
388+
val((result (error u))) ::= 0x00 => ok
389+
| 0x01 v:<val(u)> => (error v)
390+
val((result t (error u))) ::= 0x00 v:<val(t)> => (ok v)
391+
| 0x01 v:<val(u)> => (error v)
392+
```
393+
394+
Notes:
395+
* Reused Core binary rules:
396+
- [`core:name`]
397+
- [`core:s8`]
398+
- [`core:s16`]
399+
- [`core:s32`]
400+
- [`core:s64`]
401+
- [`core:u8`]
402+
- [`core:u16`]
403+
- [`core:u32`]
404+
- [`core:u64`]
405+
- [`core:uN`]
406+
- [`core:f32`]
407+
- [`core:f64`]
408+
* `&` operator is used to denote bitwise AND operation, which performs AND on every bit of two numbers in their binary form
409+
* `isnan` is a function, which takes a floating point number as a parameter and returns `true` iff it represents a NaN as defined in [IEEE 754 standard]
410+
350411
## Name Section
351412

352413
Like the core wasm [name
@@ -376,7 +437,17 @@ appear once within a `name` section, for example component instances can only be
376437
named once.
377438

378439

440+
[`core:s8`]: https://webassembly.github.io/spec/core/binary/values.html#integers
441+
[`core:u8`]: https://webassembly.github.io/spec/core/binary/values.html#integers
442+
[`core:s16`]: https://webassembly.github.io/spec/core/binary/values.html#integers
443+
[`core:u16`]: https://webassembly.github.io/spec/core/binary/values.html#integers
444+
[`core:s32`]: https://webassembly.github.io/spec/core/binary/values.html#integers
379445
[`core:u32`]: https://webassembly.github.io/spec/core/binary/values.html#integers
446+
[`core:s64`]: https://webassembly.github.io/spec/core/binary/values.html#integers
447+
[`core:u64`]: https://webassembly.github.io/spec/core/binary/values.html#integers
448+
[`core:uN`]: https://webassembly.github.io/spec/core/binary/values.html#integers
449+
[`core:f32`]: https://webassembly.github.io/spec/core/binary/values.html#floating-point
450+
[`core:f64`]: https://webassembly.github.io/spec/core/binary/values.html#floating-point
380451
[`core:section`]: https://webassembly.github.io/spec/core/binary/modules.html#binary-section
381452
[`core:custom`]: https://webassembly.github.io/spec/core/binary/modules.html#custom-section
382453
[`core:module`]: https://webassembly.github.io/spec/core/binary/modules.html#binary-module
@@ -388,3 +459,5 @@ named once.
388459

389460
[type-imports]: https://github.com/WebAssembly/proposal-type-imports/blob/master/proposals/type-imports/Overview.md
390461
[module-linking]: https://github.com/WebAssembly/module-linking/blob/main/proposals/module-linking/Explainer.md
462+
463+
[IEEE 754 standard]: https://ieeexplore.ieee.org/document/8766229

design/mvp/Explainer.md

Lines changed: 159 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ JavaScript runtimes. For a more user-focused explanation, take a look at the
2323
* [Canonical definitions](#canonical-definitions)
2424
* [Canonical ABI](#canonical-built-ins)
2525
* [Canonical built-ins](#canonical-built-ins)
26-
* [Start definitions](#-start-definitions)
26+
* [Value definitions](#value-definitions)
27+
* [Start definitions](#start-definitions)
2728
* [Import and export definitions](#import-and-export-definitions)
2829
* [Component invariants](#component-invariants)
2930
* [JavaScript embedding](#JavaScript-embedding)
@@ -87,6 +88,7 @@ definition ::= core-prefix(<core:module>)
8788
| <start> 🪺
8889
| <import>
8990
| <export>
91+
| <value> 🪙
9092
9193
where core-prefix(X) parses '(' 'core' Y ')' when X parses '(' Y ')'
9294
```
@@ -296,7 +298,7 @@ contain any valid UTF-8 string).
296298

297299
🪙 The `value` sort refers to a value that is provided and consumed during
298300
instantiation. How this works is described in the
299-
[start definitions](#start-definitions) section.
301+
[value definitions](#value-definitions) section.
300302

301303
To see a non-trivial example of component instantiation, we'll first need to
302304
introduce a few other definitions below that allow components to import, define
@@ -564,10 +566,12 @@ externdesc ::= (<sort> (type <u32>) )
564566
| <functype>
565567
| <componenttype>
566568
| <instancetype>
567-
| (value <valtype>) 🪙
569+
| (value <valuebound>) 🪙
568570
| (type <typebound>)
569571
typebound ::= (eq <typeidx>)
570572
| (sub resource)
573+
valuebound ::= (eq <valueidx>) 🪙
574+
| <valtype> 🪙
571575
572576
where bind-id(X) parses '(' sort <id>? Y ')' when X parses '(' sort Y ')'
573577
```
@@ -733,7 +737,7 @@ definitions.
733737

734738
🪙 The `value` case of `externdesc` describes a runtime value that is imported or
735739
exported at instantiation time as described in the
736-
[start definitions](#start-definitions) section below.
740+
[value definitions](#value-definitions) section below.
737741

738742
The `type` case of `externdesc` describes an imported or exported type along
739743
with its "bound":
@@ -1348,22 +1352,100 @@ number of threads that can be expected to execute concurrently.
13481352
See the [CanonicalABI.md](CanonicalABI.md#canonical-definitions) for detailed
13491353
definitions of each of these built-ins and their interactions.
13501354

1355+
### 🪙 Value Definitions
13511356

1352-
### 🪙 Start Definitions
1357+
Value definitions (in the value index space) are like immutable `global` definitions
1358+
in Core WebAssembly except that validation requires them to be consumed exactly
1359+
once at instantiation-time (i.e., they are [linear]).
1360+
1361+
Components may define values in the value index space using following syntax:
13531362

1354-
Like modules, components can have start functions that are called during
1355-
instantiation. Unlike modules, components can call start functions at multiple
1356-
points during instantiation with each such call having parameters and results.
1357-
Thus, `start` definitions in components look like function calls:
13581363
```ebnf
1359-
start ::= (start <funcidx> (value <valueidx>)* (result (value <id>?))*)
1364+
value ::= (value <id>? <valtype> <val>)
1365+
val ::= false | true
1366+
| <core:i64>
1367+
| <core:f64> | NaN
1368+
| '<core:char>'
1369+
| <core:name>
1370+
| (record <val>+)
1371+
| (variant "<label>" <val>?)
1372+
| (list <val>*)
1373+
| (tuple <val>+)
1374+
| (flags "<label>"*)
1375+
| (enum "<label>")
1376+
| none | (some <val>)
1377+
| ok | (ok <val>) | error | (error <val>)
1378+
```
1379+
1380+
The validation rules for `value` require the `val` to match the `valtype`. For example:
1381+
```wasm
1382+
(component
1383+
(value $a bool true)
1384+
(value $b u8 1)
1385+
(value $c u16 2)
1386+
(value $d u32 3)
1387+
(value $e u64 4)
1388+
(value $f u8 5)
1389+
(value $g u16 6)
1390+
(value $h u32 7)
1391+
(value $i u64 8)
1392+
(value $j f32 9.1)
1393+
(value $k f64 9.2)
1394+
(value $l char 'a')
1395+
(value $m string "hello")
1396+
(value $n (record (field "a" bool) (field "b" u8)) (record true 1))
1397+
(value $o (variant (case "a" bool) (case "b" u8)) (variant "b" 1))
1398+
(value $p (list (result (option u8)))
1399+
(list
1400+
error
1401+
(ok (some 1))
1402+
(ok none)
1403+
error
1404+
(ok (some 2))
1405+
)
1406+
)
1407+
(value $q (tuple u8 u16 u32) (tuple 1 2 3))
1408+
1409+
(type $abc (flags "a" "b" "c"))
1410+
(value $r $abc (flags "a" "c"))
1411+
1412+
(value $s (enum "a" "b" "c") (enum "b"))
1413+
1414+
(type $complex
1415+
(tuple
1416+
(record
1417+
(field "a" (option string))
1418+
(field "b" (tuple (option u8) string))
1419+
)
1420+
(list char)
1421+
$abc
1422+
string
1423+
)
1424+
)
1425+
(value $complex1 (type $complex)
1426+
(tuple
1427+
(record
1428+
none
1429+
(tuple none "empty")
1430+
)
1431+
(list)
1432+
(flags)
1433+
""
1434+
)
1435+
)
1436+
(value $complex2 (type $complex)
1437+
(tuple
1438+
(record
1439+
(some "example")
1440+
(tuple (some 42) "hello")
1441+
)
1442+
(list 'a' 'b' 'c')
1443+
(flags "b" "a")
1444+
"hi"
1445+
)
1446+
)
1447+
)
13601448
```
1361-
The `(value <valueidx>)*` list specifies the arguments passed to `funcidx` by
1362-
indexing into the *value index space*. Value definitions (in the value index
1363-
space) are like immutable `global` definitions in Core WebAssembly except that
1364-
validation requires them to be consumed exactly once at instantiation-time
1365-
(i.e., they are [linear]). The arity and types of the two value lists are
1366-
validated to match the signature of `funcidx`.
13671449

13681450
As with all definition sorts, values may be imported and exported by
13691451
components. As an example value import:
@@ -1373,6 +1455,45 @@ components. As an example value import:
13731455
As this example suggests, value imports can serve as generalized [environment
13741456
variables], allowing not just `string`, but the full range of `valtype`.
13751457

1458+
Values can also be exported. For example:
1459+
```wasm
1460+
(component
1461+
(import "system-port" (value $port u16))
1462+
(value $url string "https://example.com")
1463+
(export "default-url" (value $url))
1464+
(export "default-port" (value $port))
1465+
)
1466+
```
1467+
The inferred type of this component is:
1468+
```wasm
1469+
(component
1470+
(import "system-port" (value $port u16))
1471+
(value $url string "https://example.com")
1472+
(export "default-url" (value (eq $url)))
1473+
(export "default-port" (value (eq $port)))
1474+
)
1475+
```
1476+
Thus, by default, the precise constant or import being exported is propagated
1477+
into the component's type and thus its public interface. In this way, value exports
1478+
can act as semantic configuration data provided by the component to the host
1479+
or other client tooling.
1480+
Components can also keep the exact value being exported abstract (so that the
1481+
precise value is not part of the type and public interface) using the "type ascription"
1482+
feature mentioned in the [imports and exports](#import-and-export-definitions) section below.
1483+
1484+
### 🪙 Start Definitions
1485+
1486+
Like modules, components can have start functions that are called during
1487+
instantiation. Unlike modules, components can call start functions at multiple
1488+
points during instantiation with each such call having parameters and results.
1489+
Thus, `start` definitions in components look like function calls:
1490+
```ebnf
1491+
start ::= (start <funcidx> (value <valueidx>)* (result (value <id>?))*)
1492+
```
1493+
The `(value <valueidx>)*` list specifies the arguments passed to `funcidx` by
1494+
indexing into the *value index space*. The arity and types of the two value lists are
1495+
validated to match the signature of `funcidx`.
1496+
13761497
With this, we can define a component that imports a string and computes a new
13771498
exported string at instantiation time:
13781499
```wasm
@@ -1650,6 +1771,25 @@ the standard [avoidance problem] that appears in module systems with abstract
16501771
types. In particular, it ensures that a client of a component is able to
16511772
externally define a type compatible with the exports of the component.
16521773

1774+
Similar to type exports, value exports may also ascribe a type to keep the precise
1775+
value from becoming part of the type and public interface.
1776+
1777+
For example:
1778+
```wasm
1779+
(component
1780+
(value $url string "https://example.com")
1781+
(export "default-url" (value $url) (value string))
1782+
)
1783+
```
1784+
1785+
The inferred type of this component is:
1786+
```wasm
1787+
(component
1788+
(export "default-url" (value string))
1789+
)
1790+
```
1791+
1792+
Note, that the `url` value definition is absent from the component type
16531793

16541794
## Component Invariants
16551795

@@ -1934,6 +2074,9 @@ and will be added over the coming months to complete the MVP proposal:
19342074
[Index Space]: https://webassembly.github.io/spec/core/syntax/modules.html#indices
19352075
[Abbreviations]: https://webassembly.github.io/spec/core/text/conventions.html#abbreviations
19362076

2077+
[`core:i64`]: https://webassembly.github.io/spec/core/syntax/values.html#integers
2078+
[`core:f64`]: https://webassembly.github.io/spec/core/syntax/values.html#floating-point
2079+
[`core:char`]: https://webassembly.github.io/spec/core/syntax/values.html#syntax-name
19372080
[`core:name`]: https://webassembly.github.io/spec/core/syntax/values.html#syntax-name
19382081
[`core:module`]: https://webassembly.github.io/spec/core/text/modules.html#text-module
19392082
[`core:type`]: https://webassembly.github.io/spec/core/text/modules.html#types

0 commit comments

Comments
 (0)