component-model

Component Model Binary Format Explainer

This document defines the binary format for the AST defined in the explainer. The top-level production is component and the convention is that a file suffixed in .wasm may contain either a core:module or a component, using the layer field to discriminate between the two in the first 8 bytes (see below for more details).

Note: this document is not meant to completely define the decoding or validation rules, but rather merge the minimal need-to-know elements of both, with just enough detail to create a prototype. A complete definition of the binary format and validation will be present in the formal specification.

See the explainer introduction for an explanation of 🪙.

Component Definitions

(See Component Definitions in the explainer.)

component ::= <preamble> s*:<section>*            => (component flatten(s*))
preamble  ::= <magic> <version> <layer>
magic     ::= 0x00 0x61 0x73 0x6D
version   ::= 0x0d 0x00
layer     ::= 0x01 0x00
section   ::=    section_0(<core:custom>)         => ϵ
            | m:section_1(<core:module>)          => [core-prefix(m)]
            | i*:section_2(vec(<core:instance>))  => core-prefix(i)*
            | t*:section_3(vec(<core:type>))      => core-prefix(t)*
            | c: section_4(<component>)           => [c]
            | i*:section_5(vec(<instance>))       => i*
            | a*:section_6(vec(<alias>))          => a*
            | t*:section_7(vec(<type>))           => t*
            | c*:section_8(vec(<canon>))          => c*
            | s: section_9(<start>)               => [s]
            | i*:section_10(vec(<import>))        => i*
            | e*:section_11(vec(<export>))        => e*
            | v*:section_12(vec(<value>))         => v* 🪙

Notes:

Instance Definitions

(See Instance Definitions in the explainer.)

core:instance       ::= ie:<core:instanceexpr>                             => (instance ie)
core:instanceexpr   ::= 0x00 m:<moduleidx> arg*:vec(<core:instantiatearg>) => (instantiate m arg*)
                      | 0x01 e*:vec(<core:inlineexport>)                   => e*
core:instantiatearg ::= n:<core:name> 0x12 i:<instanceidx>                 => (with n (instance i))
core:sortidx        ::= sort:<core:sort> idx:<u32>                         => (sort idx)
core:sort           ::= 0x00                                               => func
                      | 0x01                                               => table
                      | 0x02                                               => memory
                      | 0x03                                               => global
                      | 0x10                                               => type
                      | 0x11                                               => module
                      | 0x12                                               => instance
core:inlineexport   ::= n:<core:name> si:<core:sortidx>                    => (export n si)

instance            ::= ie:<instanceexpr>                                  => (instance ie)
instanceexpr        ::= 0x00 c:<componentidx> arg*:vec(<instantiatearg>)   => (instantiate c arg*)
                      | 0x01 e*:vec(<inlineexport>)                        => e*
instantiatearg      ::= n:<name>  si:<sortidx>                             => (with n si)
name                ::= n:<core:name>                                      => n
sortidx             ::= sort:<sort> idx:<u32>                              => (sort idx)
sort                ::= 0x00 cs:<core:sort>                                => core cs
                      | 0x01                                               => func
                      | 0x02                                               => value 🪙
                      | 0x03                                               => type
                      | 0x04                                               => component
                      | 0x05                                               => instance
inlineexport        ::= n:<exportname> si:<sortidx>                        => (export n si)

Notes:

Alias Definitions

(See Alias Definitions in the explainer.)

alias       ::= s:<sort> t:<aliastarget>                => (alias t (s))
aliastarget ::= 0x00 i:<instanceidx> n:<name>           => export i n
              | 0x01 i:<core:instanceidx> n:<core:name> => core export i n
              | 0x02 ct:<u32> idx:<u32>                 => outer ct idx

Notes:

Type Definitions

(See Type Definitions in the explainer.)

core:type        ::= dt:<core:deftype>                  => (type dt)        (GC proposal)
core:deftype     ::= ft:<core:functype>                 => ft               (WebAssembly 1.0)
                   | st:<core:structtype>               => st               (GC proposal)
                   | at:<core:arraytype>                => at               (GC proposal)
                   | mt:<core:moduletype>               => mt
core:moduletype  ::= 0x50 md*:vec(<core:moduledecl>)    => (module md*)
core:moduledecl  ::= 0x00 i:<core:import>               => i
                   | 0x01 t:<core:type>                 => t
                   | 0x02 a:<core:alias>                => a
                   | 0x03 e:<core:exportdecl>           => e
core:alias       ::= s:<core:sort> t:<core:aliastarget> => (alias t (s))
core:aliastarget ::= 0x01 ct:<u32> idx:<u32>            => outer ct idx
core:importdecl  ::= i:<core:import>                    => i
core:exportdecl  ::= n:<core:name> d:<core:importdesc>  => (export n d)

Notes:

type          ::= dt:<deftype>                            => (type dt)
deftype       ::= dvt:<defvaltype>                        => dvt
                | ft:<functype>                           => ft
                | ct:<componenttype>                      => ct
                | it:<instancetype>                       => it
primvaltype   ::= 0x7f                                    => bool
                | 0x7e                                    => s8
                | 0x7d                                    => u8
                | 0x7c                                    => s16
                | 0x7b                                    => u16
                | 0x7a                                    => s32
                | 0x79                                    => u32
                | 0x78                                    => s64
                | 0x77                                    => u64
                | 0x76                                    => f32
                | 0x75                                    => f64
                | 0x74                                    => char
                | 0x73                                    => string
defvaltype    ::= pvt:<primvaltype>                       => pvt
                | 0x72 lt*:vec(<labelvaltype>)            => (record (field lt)*)    (if |lt*| > 0)
                | 0x71 case*:vec(<case>)                  => (variant case+) (if |case*| > 0)
                | 0x70 t:<valtype>                        => (list t)
                | 0x6f t*:vec(<valtype>)                  => (tuple t+)    (if |t*| > 0)
                | 0x6e l*:vec(<label'>)                   => (flags l+)    (if |l*| > 0)
                | 0x6d l*:vec(<label'>)                   => (enum l+)     (if |l*| > 0)
                | 0x6b t:<valtype>                        => (option t)
                | 0x6a t?:<valtype>? u?:<valtype>?        => (result t? (error u)?)
                | 0x69 i:<typeidx>                        => (own i)
                | 0x68 i:<typeidx>                        => (borrow i)
labelvaltype  ::= l:<label'> t:<valtype>                  => l t
case          ::= l:<label'> t?:<valtype>? 0x00           => (case l t?)
label'        ::= len:<u32> l:<label>                     => l    (if len = |l|)
<T>?          ::= 0x00                                    =>
                | 0x01 t:<T>                              => t
valtype       ::= i:<typeidx>                             => i
                | pvt:<primvaltype>                       => pvt
resourcetype  ::= 0x3f 0x7f f?:<funcidx>?                 => (resource (rep i32) (dtor f)?)
functype      ::= 0x40 ps:<paramlist> rs:<resultlist>     => (func ps rs)
paramlist     ::= lt*:vec(<labelvaltype>)                 => (param lt)*
resultlist    ::= 0x00 t:<valtype>                        => (result t)
                | 0x01 lt*:vec(<labelvaltype>)            => (result lt)*
componenttype ::= 0x41 cd*:vec(<componentdecl>)           => (component cd*)
instancetype  ::= 0x42 id*:vec(<instancedecl>)            => (instance id*)
componentdecl ::= 0x03 id:<importdecl>                    => id
                | id:<instancedecl>                       => id
instancedecl  ::= 0x00 t:<core:type>                      => t
                | 0x01 t:<type>                           => t
                | 0x02 a:<alias>                          => a
                | 0x04 ed:<exportdecl>                    => ed
importdecl    ::= in:<importname'> ed:<externdesc>        => (import in ed)
exportdecl    ::= en:<exportname'> ed:<externdesc>        => (export en ed)
externdesc    ::= 0x00 0x11 i:<core:typeidx>              => (core module (type i))
                | 0x01 i:<typeidx>                        => (func (type i))
                | 0x02 b:<valuebound>                     => (value b) 🪙
                | 0x03 b:<typebound>                      => (type b)
                | 0x04 i:<typeidx>                        => (component (type i))
                | 0x05 i:<typeidx>                        => (instance (type i))
typebound     ::= 0x00 i:<typeidx>                        => (eq i)
                | 0x01                                    => (sub resource)
valuebound    ::= 0x00 i:<valueidx>                       => (eq i) 🪙
                | 0x01 t:<valtype>                        => t 🪙

Notes:

Canonical Definitions

(See Canonical Definitions in the explainer.)

canon    ::= 0x00 0x00 f:<core:funcidx> opts:<opts> ft:<typeidx> => (canon lift f opts type-index-space[ft])
           | 0x01 0x00 f:<funcidx> opts:<opts>                   => (canon lower f opts (core func))
           | 0x02 rt:<typeidx>                                   => (canon resource.new rt (core func))
           | 0x03 rt:<typeidx>                                   => (canon resource.drop rt (core func))
           | 0x04 rt:<typeidx>                                   => (canon resource.rep rt (core func))
           | 0x05 ft:<typeidx>                                   => (canon thread.spawn ft (core func))
           | 0x06                                                => (canon thread.hw_concurrency (core func))
opts     ::= opt*:vec(<canonopt>)                                => opt*
canonopt ::= 0x00                                                => string-encoding=utf8
           | 0x01                                                => string-encoding=utf16
           | 0x02                                                => string-encoding=latin1+utf16
           | 0x03 m:<core:memidx>                                => (memory m)
           | 0x04 f:<core:funcidx>                               => (realloc f)
           | 0x05 f:<core:funcidx>                               => (post-return f)

Notes:

🪙 Start Definitions

(See Start Definitions in the explainer.)

start ::= f:<funcidx> arg*:vec(<valueidx>) r:<u32> => (start f (value arg)* (result (value))ʳ)

Notes:

In addition to the type-compatibility checks mentioned above, the validation rules for value definitions additionally require that each value is consumed exactly once. Thus, during validation, each value has an associated “consumed” boolean flag. When a value is first added to the value index space (via import, instance, alias or start), the flag is clear. When a value is used (via export, instantiate or start), the flag is set. After validating the last definition of a component, validation requires all values’ flags are set.

Import and Export Definitions

(See Import and Export Definitions in the explainer.)

import      ::= in:<importname'> ed:<externdesc>                     => (import in ed)
export      ::= en:<exportname'> si:<sortidx> ed?:<externdesc>?      => (export en si ed?)
importname' ::= 0x00 len:<u32> in:<importname>                       => in  (if len = |in|)
exportname' ::= 0x00 len:<u32> en:<exportname>                       => en  (if len = |en|)

Notes:

🪙 Value Definitions

(See Value Definitions in the explainer.)

value                      ::= t:<valtype> len:<core:u32> v:<val(t)>   => (value t v) (where len = ||v||)
val(bool)                  ::= 0x00                                    => false
                             | 0x01                                    => true
val(u8)                    ::= v:<core:byte>                           => v
val(s8)                    ::= v:<core:byte>                           => v' (where v' = v if v < 128 else (v - 256))
val(s16)                   ::= v:<core:s16>                            => v
val(u16)                   ::= v:<core:u16>                            => v
val(s32)                   ::= v:<core:s32>                            => v
val(u32)                   ::= v:<core:u32>                            => v
val(s64)                   ::= v:<core:s64>                            => v
val(u64)                   ::= v:<core:u64>                            => v
val(f32)                   ::= v:<core:f32>                            => v (if !isnan(v))
                             | 0x00 0x00 0xC0 0x7F                     => nan
val(f64)                   ::= v:<core:f64>                            => v (if !isnan(v))
                             | 0x00 0x00 0x00 0x00 0x00 0x00 0xF8 0x7F => nan
val(char)                  ::= b*:<core:byte>*                         => c (where b* = core:utf8(c))
val(string)                ::= v:<core:name>                           => v
val(i:<typeidx>)           ::= v:<val(type-index-space[i])>            => v
val((record (field l t)+)) ::= v+:<val(t)>+                            => (record v+)
val((variant (case l t?)+) ::= i:<core:u32> v?:<val(t[i])>?            => (variant l[i] v?)
val((list t))              ::= v:vec(<val(t)>)                         => (list v)
val((tuple t+))            ::= v+:<val(t)>+                            => (tuple v+)
val((flags l+))            ::= (v:<core:byte>)^N                       => (flags (l[i] for i in 0..|l+|-1 if v[floor(i / 8)] & 2^(i mod 8) > 0)) (where N = ceil(|l+| / 8))
val((enum l+))             ::= i:<core:u32>                            => (enum l[i])
val((option t))            ::= 0x00                                    => none
                             | 0x01 v:<val(t)>                         => (some v)
val((result))              ::= 0x00                                    => ok
                             | 0x01                                    => error
val((result t))            ::= 0x00 v:<val(t)>                         => (ok v)
                             | 0x01                                    => error
val((result (error u)))    ::= 0x00                                    => ok
                             | 0x01 v:<val(u)>                         => (error v)
val((result t (error u)))  ::= 0x00 v:<val(t)>                         => (ok v)
                             | 0x01 v:<val(u)>                         => (error v)

Notes:

Name Section

Like the core wasm name section a similar name custom section is specified here for components to be able to name all the declarations that can happen within a component. Similarly like its core wasm counterpart validity of this custom section is not required and engines should not reject components which have an invalid name section.

namesec    ::= section_0(namedata)
namedata   ::= n:<name>                (if n = 'component-name')
               name:<componentnamesubsec>?
               sortnames*:<sortnamesubsec>*
namesubsection_N(B) ::= N:<byte> size:<u32> B     (if size == |B|)

componentnamesubsec ::= namesubsection_0(<name>)
sortnamesubsec ::= namesubsection_1(<sortnames>)
sortnames ::= sort:<sort> names:<namemap>

namemap ::= names:vec(<nameassoc>)
nameassoc ::= idx:<u32> name:<name>

where namemap is the same as for core wasm. A particular sort should only appear once within a name section, for example component instances can only be named once.