Modules

Modules are valid when all the components they contain are valid. Furthermore, most definitions are themselves classified with a suitable type.

Types

The sequence of types defined in a module is validated incrementally, yielding a suitable context.

type

  • If the sequence is empty, then:

    • The context C must be empty.

    • Then the type sequence is valid.

  • Otherwise:

    • Let the recursive type rectype be the last element in the sequence.

    • The sequence without rectype must be valid for some context C.

    • Let the type index x be the length of C.types, i.e., the first type index free in C.

    • Let the sequence of defined types deftype be the result rollx(rectype) of rolling up into its sequence of defined types.

    • The recursive type rectype must be valid under the context C for type index x.

    • The current context C be the same as C, but with deftype appended to types.

    • Then the type sequence is valid.

{}ϵok
CtypeokC=Cwithtypes=C.types roll|C.types|(rectype)Crectype ok(|C.types|)Ctype rectypeok

Note

Despite the appearance, the context C is effectively an _output_ of this judgement.

Functions

Functions func are classified by defined types that expand to function types of the form func [t1][t2].

{type x,locals t,body expr}

  • The defined type C.types[x] must be a function type.

  • Let func [t1][t2] be the expansion of the defined type C.types[x].

  • For each local declared by a value type t in t:

  • Let localtype be the concatenation of all localtypei.

  • Let C be the same context as C, but with:

    • locals set to the sequence of value types (set t1) localtype, concatenating parameters and locals,

    • labels set to the singular sequence containing only result type [t2].

    • return set to the result type [t2].

  • Under the context C, the expression expr must be valid with type [t2].

  • Then the function definition is valid with type C.types[x].

expand(C.types[x])=func [t1][t2](C{type t}:init t)C,locals(set t1) (init t),labels [t2],return [t2]expr:[t2]C{type x,locals {type t},body expr}:C.types[x]

Locals

Locals are classified with local types.

{type valtype}

CtokCtdefaultableC{type t}:set t
CtokC{type t}:unset t

Note

For cases where both rules are applicable, the former yields the more permissable type.

Tables

Tables table are classified by table types.

{type tabletype,init expr}

Ctabletypeoktabletype=limits tCexpr:[t]CexprconstC{type tabletype,init expr}:tabletype

Memories

Memories mem are classified by memory types.

{type memtype}

  • The memory type memtype must be valid.

  • Then the memory definition is valid with type memtype.

CmemtypeokC{type memtype}:memtype

Globals

Globals global are classified by global types of the form mut t.

Sequences of globals are handled incrementally, such that each definition has access to previous definitions.

{type mut t,init expr}

Cmut tokCexpr:[t]CexprconstC{type mut t,init expr}:mut t

global

  • If the sequence is empty, then it is valid with the empty sequence of global types.

  • Else:

    • The first global definition must be valid with some type global type gt1.

    • Let C be the same context as C, but with the global type gt1 apppended to the globals vector.

    • Under context C, the remainder of the sequence must be valid with some sequence gt of global types.

    • Then the sequence is valid with the sequence of global types consisting of gt1 prepended to gt.

 Cϵ:ϵCglobal1:gt1C{globals gt1}global:gtCglobal1 global:gt1 gt

Element Segments

Element segments elem are classified by the reference type of their elements.

{type t,init e,mode elemmode}

Ctok(Ce:[t])(Ceconst)Celemmode:tCttC{type t,init e,mode elemmode}:t

passive

CreftypeokCpassive:reftype

active {table x,offset expr}

  • The table C.tables[x] must be defined in the context.

  • Let limits t be the table type C.tables[x].

  • The expression expr must be valid with result type [i32].

  • The expression expr must be constant.

  • Then the element mode is valid with reference type t.

C.tables[x]=limits tCexpr:[i32]CexprconstCactive {table x,offset expr}:t

declarative

CreftypeokCdeclarative:reftype

Data Segments

Data segments data are not classified by any type but merely checked for well-formedness.

{init b,mode datamode}

  • The data mode datamode must be valid.

  • Then the data segment is valid.

CdatamodeokC{init b,mode datamode}ok

passive

  • The data mode is valid.

Cpassiveok

active {memory x,offset expr}

  • The memory C.mems[x] must be defined in the context.

  • The expression expr must be valid with result type [i32].

  • The expression expr must be constant.

  • Then the data mode is valid.

C.mems[x]=limitsCexpr:[i32]CexprconstCactive {memory x,offset expr}ok

Start Function

Start function declarations start are not classified by any type.

{func x}

  • The function C.funcs[x] must be defined in the context.

  • The expansion of C.funcs[x] must be a function type func [][].

  • Then the start function is valid.

expand(C.funcs[x])=func [][]C{func x}ok

Exports

Exports export and export descriptions exportdesc are classified by their external type.

{name name,desc exportdesc}

  • The export description exportdesc must be valid with external type externtype.

  • Then the export is valid with external type externtype.

Cexportdesc:externtypeC{name name,desc exportdesc}:externtype

func x

  • The function C.funcs[x] must be defined in the context.

  • Let dt be the defined type C.funcs[x].

  • Then the export description is valid with external type func dt.

C.funcs[x]=dtCfunc x:func dt

table x

  • The table C.tables[x] must be defined in the context.

  • Then the export description is valid with external type table C.tables[x].

C.tables[x]=tabletypeCtable x:table tabletype

mem x

  • The memory C.mems[x] must be defined in the context.

  • Then the export description is valid with external type mem C.mems[x].

C.mems[x]=memtypeCmem x:mem memtype

global x

  • The global C.globals[x] must be defined in the context.

  • Then the export description is valid with external type global C.globals[x].

C.globals[x]=globaltypeCglobal x:global globaltype

Imports

Imports import and import descriptions importdesc are classified by external types.

{module name1,name name2,desc importdesc}

  • The import description importdesc must be valid with type externtype.

  • Then the import is valid with type externtype.

Cimportdesc:externtypeC{module name1,name name2,desc importdesc}:externtype

func x

expand(C.types[x])=func functypeCfunc x:func C.types[x]

table tabletype

  • The table type tabletype must be valid.

  • Then the import description is valid with type table tabletype.

CtabletypeokCtable tabletype:table tabletype

mem memtype

  • The memory type memtype must be valid.

  • Then the import description is valid with type mem memtype.

CmemtypeokCmem memtype:mem memtype

global globaltype

  • The global type globaltype must be valid.

  • Then the import description is valid with type global globaltype.

CglobaltypeokCglobal globaltype:global globaltype

Modules

Modules are classified by their mapping from the external types of their imports to those of their exports.

A module is entirely closed, that is, its components can only refer to definitions that appear in the module itself. Consequently, no initial context is required. Instead, the context C for validation of the module’s content is constructed from the definitions in the module.

The external types classifying a module may contain free type indices that refer to types defined within the module.

  • Let module be the module to validate.

  • The types module.types must be valid yielding a context C0.

  • Let C be a context where:

    • C.types is C0.types,

    • C.funcs is funcs(it) concatenated with dt, with the import’s external types it and the internal defined types dt as determined below,

    • C.tables is tables(it) concatenated with tt, with the import’s external types it and the internal table types tt as determined below,

    • C.mems is mems(it) concatenated with mt, with the import’s external types it and the internal memory types mt as determined below,

    • C.globals is globals(it) concatenated with gt, with the import’s external types it and the internal global types gt as determined below,

    • C.elems is rt as determined below,

    • C.datas is okn, where n is the length of the vector module.datas,

    • C.locals is empty,

    • C.labels is empty,

    • C.return is empty.

    • C.refs is the set funcidx(modulewithfuncs=ϵwithstart=ϵ), i.e., the set of function indices occurring in the module, except in its functions or start function.

  • Let C be the context where:

    • C.globals is the sequence globals(it),

    • C.types is the same as C.types,

    • C.funcs is the same as C.funcs,

    • C.refs is the same as C.refs,

    • all other fields are empty.

  • Under the context C:

  • Under the context C:

    • For each funci in module.funcs, the definition funci must be valid with a defined type dti.

    • For each elemi in module.elems, the segment elemi must be valid with reference type rti.

    • For each datai in module.datas, the segment datai must be valid.

    • If module.start is non-empty, then module.start must be valid.

    • For each importi in module.imports, the segment importi must be valid with an external type iti.

    • For each exporti in module.exports, the segment exporti must be valid with external type eti.

  • Let dt be the concatenation of the internal function types dti, in index order.

  • Let tt be the concatenation of the internal table types tti, in index order.

  • Let mt be the concatenation of the internal memory types mti, in index order.

  • Let rt be the concatenation of the reference types rti, in index order.

  • Let it be the concatenation of external types iti of the imports, in index order.

  • Let et be the concatenation of external types eti of the exports, in index order.

  • The length of C.mems must not be larger than 1.

  • All export names exporti.name must be different.

  • Then the module is valid with external types itet.

C0typeokCglobal:gt(Ctable:tt)(Cmem:mt)(Cfunc:dt)(Celem:rt)(Cdataok)n(Cstartok)?(Cimport:it)(Cexport:et)idt=funcs(it)itt=tables(it)imt=mems(it)igt=globals(it)x=funcidx(modulewithfuncs=ϵwithstart=ϵ)C={types C0.types,funcs idtdt,tables itttt,mems imtmt,globals igtgt,elems rt,datas okn,refs x}C={types C0.types,globals igt,funcs (C.funcs),refs (C.refs)}|C.mems|1(export.name) disjointmodule={types type,funcs func,tables table,mems mem,globals global,elems elem,datas datan,start start?,imports import,exports export}module:itet

Note

All functions in a module are mutually recursive. Consequently, the definition of the context C in this rule is recursive: it depends on the outcome of validation of the function, table, memory, and global definitions contained in the module, which itself depends on C. However, this recursion is just a specification device. All types needed to construct C can easily be determined from a simple pre-pass over the module that does not perform any actual validation.

Globals, however, are not recursive but evaluated sequentially, such that each constant expressions only has access to imported or previously defined globals.

Note

The restriction on the number of memories may be lifted in future versions of WebAssembly.