package wasm import ( "bytes" "fmt" ) // DecodeModule parses the WebAssembly Binary Format (%.wasm) into a Module. This function returns when the input is // exhausted or an error occurs. The result can be initialized for use via Store.Instantiate. // // Here's a description of the return values: // * result is the module parsed or nil on error // * err is a FormatError invoking the parser, dangling block comments or unexpected characters. // See binary.DecodeModule and text.DecodeModule type DecodeModule func( wasm []byte, features CoreFeatures, memorySizer func(minPages uint32, maxPages *uint32) (min, capacity, max uint32), ) (result *Module, err error) // EncodeModule encodes the given module into a byte slice depending on the format of the implementation. // See binary.EncodeModule type EncodeModule func(m *Module) (bytes []byte) // The wazero specific limitation described at RATIONALE.md. // TL;DR; We multiply by 8 (to get offsets in bytes) and the multiplication result must be less than 32bit max const ( MaximumGlobals = uint32(1 << 27) MaximumFunctionIndex = uint32(1 << 27) MaximumTableIndex = uint32(1 << 27) ) // Module is a WebAssembly binary representation. // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#modules%E2%91%A8 // // Differences from the specification: // * NameSection is the only key ("name") decoded from the SectionIDCustom. // * ExportSection is represented as a map for lookup convenience. // * Code.GoFunc is contains any go `func`. It may be present when Code.Body is not. type Module struct { // TypeSection contains the unique FunctionType of functions imported or defined in this module. // // Note: Currently, there is no type ambiguity in the index as WebAssembly 1.0 only defines function type. // In the future, other types may be introduced to support CoreFeatures such as module linking. // // Note: In the Binary Format, this is SectionIDType. // // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#types%E2%91%A0%E2%91%A0 TypeSection []*FunctionType // ImportSection contains imported functions, tables, memories or globals required for instantiation // (Store.Instantiate). // // Note: there are no unique constraints relating to the two-level namespace of Import.Module and Import.Name. // // Note: In the Binary Format, this is SectionIDImport. // // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#import-section%E2%91%A0 ImportSection []*Import // FunctionSection contains the index in TypeSection of each function defined in this module. // // Note: The function Index namespace begins with imported functions and ends with those defined in this module. // For example, if there are two imported functions and one defined in this module, the function Index 3 is defined // in this module at FunctionSection[0]. // // Note: FunctionSection is index correlated with the CodeSection. If given the same position, ex. 2, a function // type is at TypeSection[FunctionSection[2]], while its locals and body are at CodeSection[2]. // // Note: In the Binary Format, this is SectionIDFunction. // // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#function-section%E2%91%A0 FunctionSection []Index // TableSection contains each table defined in this module. // // Note: The table Index namespace begins with imported tables and ends with those defined in this module. // For example, if there are two imported tables and one defined in this module, the table Index 3 is defined in // this module at TableSection[0]. // // Note: Version of the WebAssembly spec allows at most one table definition per module, so the // length of the TableSection can be zero or one, and can only be one if there is no imported table. // // Note: In the Binary Format, this is SectionIDTable. // // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#table-section%E2%91%A0 TableSection []*Table // MemorySection contains each memory defined in this module. // // Note: The memory Index namespace begins with imported memories and ends with those defined in this module. // For example, if there are two imported memories and one defined in this module, the memory Index 3 is defined in // this module at TableSection[0]. // // Note: Version of the WebAssembly spec allows at most one memory definition per module, so the // length of the MemorySection can be zero or one, and can only be one if there is no imported memory. // // Note: In the Binary Format, this is SectionIDMemory. // // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#memory-section%E2%91%A0 MemorySection *Memory // GlobalSection contains each global defined in this module. // // Global indexes are offset by any imported globals because the global index space begins with imports, followed by // ones defined in this module. For example, if there are two imported globals and three defined in this module, the // global at index 3 is defined in this module at GlobalSection[0]. // // Note: In the Binary Format, this is SectionIDGlobal. // // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#global-section%E2%91%A0 GlobalSection []*Global // ExportSection contains each export defined in this module. // // Note: In the Binary Format, this is SectionIDExport. // // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#exports%E2%91%A0 ExportSection []*Export // StartSection is the index of a function to call before returning from Store.Instantiate. // // Note: The index here is not the position in the FunctionSection, rather in the function index namespace, which // begins with imported functions. // // Note: In the Binary Format, this is SectionIDStart. // // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#start-section%E2%91%A0 StartSection *Index // Note: In the Binary Format, this is SectionIDElement. ElementSection []*ElementSegment // CodeSection is index-correlated with FunctionSection and contains each // function's locals and body. // // When present, the HostFunctionSection of the same index must be nil. // // Note: In the Binary Format, this is SectionIDCode. // // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#code-section%E2%91%A0 CodeSection []*Code // Note: In the Binary Format, this is SectionIDData. DataSection []*DataSegment // DataCountSection is the optional section and holds the number of data segments in the data section. // // Note: This may exist in WebAssembly 2.0 or WebAssembly 1.0 with FeatureBulkMemoryOperations. // See https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/binary/modules.html#data-count-section // See https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/appendix/changes.html#bulk-memory-and-table-instructions DataCountSection *uint32 // NameSection is set when the SectionIDCustom "name" was successfully decoded from the binary format. // // Note: This is the only SectionIDCustom defined in the WebAssembly Binary Format. // Others are read into CustomSections. // // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#name-section%E2%91%A0 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#custom-section%E2%91%A0 NameSection *NameSection // CustomSections are set when the SectionIDCustom other than "name" were successfully decoded from the binary format. // // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#custom-section%E2%91%A0 CustomSections []*CustomSection } // Index is the offset in an index namespace, not necessarily an absolute position in a Module section. This is because // index namespaces are often preceded by a corresponding type in the Module.ImportSection. // // For example, the function index namespace starts with any ExternTypeFunc in the Module.ImportSection followed by // the Module.FunctionSection // // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-index type Index = uint32 // FunctionType is a possibly empty function signature. // // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#function-types%E2%91%A0 type FunctionType struct { // Params are the possibly empty sequence of value types accepted by a function with this signature. Params []ValueType // Results are the possibly empty sequence of value types returned by a function with this signature. // // Note: In WebAssembly 1.0 (20191205), there can be at most one result. // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#result-types%E2%91%A0 Results []ValueType } // EqualsSignature returns true if the function type has the same parameters and results. func (f *FunctionType) EqualsSignature(params []ValueType, results []ValueType) bool { return bytes.Equal(f.Params, params) && bytes.Equal(f.Results, results) } // Import is the binary representation of an import indicated by Type // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-import type Import struct { Type ExternType // Module is the possibly empty primary namespace of this import Module string // Module is the possibly empty secondary namespace of this import Name string // DescFunc is the index in Module.TypeSection when Type equals ExternTypeFunc DescFunc Index // DescTable is the inlined Table when Type equals ExternTypeTable DescTable *Table // DescMem is the inlined Memory when Type equals ExternTypeMemory DescMem *Memory // DescGlobal is the inlined GlobalType when Type equals ExternTypeGlobal DescGlobal *GlobalType } // Memory describes the limits of pages (64KB) in a memory. type Memory struct { Min, Max uint32 // IsMaxEncoded true if the Max is encoded in the original source (binary or text). IsMaxEncoded bool } // Table describes the limits of elements and its type in a table. type Table struct { Min uint32 Max *uint32 Type RefType } // RefType is either RefTypeFuncref or RefTypeExternref as of WebAssembly core 2.0. type RefType = byte const ( // RefTypeFuncref represents a reference to a function. RefTypeFuncref = ValueTypeFuncref // RefTypeExternref represents a reference to a host object, which is not currently supported in wazero. RefTypeExternref = ValueTypeExternref ) func RefTypeName(t RefType) (ret string) { switch t { case RefTypeFuncref: ret = "funcref" case RefTypeExternref: ret = "externref" default: ret = fmt.Sprintf("unknown(0x%x)", t) } return } // ElementMode represents a mode of element segment which is either active, passive or declarative. // // https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/syntax/modules.html#element-segments type ElementMode = byte const ( // ElementModeActive is the mode which requires the runtime to initialize table with the contents in .Init field combined with OffsetExpr. ElementModeActive ElementMode = iota // ElementModePassive is the mode which doesn't require the runtime to initialize table, and only used with OpcodeTableInitName. ElementModePassive // ElementModeDeclarative is introduced in reference-types proposal which can be used to declare function indexes used by OpcodeRefFunc. ElementModeDeclarative ) // ElementSegment are initialization instructions for a TableInstance // // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#syntax-elem type ElementSegment struct { // OffsetExpr returns the table element offset to apply to Init indices. // Note: This can be validated prior to instantiation unless it includes OpcodeGlobalGet (an imported global). // Note: This is only set when Mode is active. OffsetExpr *ConstantExpression // TableIndex is the table's index to which this element segment is applied. // Note: This is used if and only if the Mode is active. TableIndex Index // Followings are set/used regardless of the Mode. // Init indices are (nullable) table elements where each index is the function index by which the module initialize the table. Init []*Index // Type holds the type of this element segment, which is the RefType in WebAssembly 2.0. Type RefType // Mode is the mode of this element segment. Mode ElementMode } // TableInstance represents a table of (RefTypeFuncref) elements in a module. // // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#table-instances%E2%91%A0 type TableInstance struct { // References holds references whose type is either RefTypeFuncref or RefTypeExternref (unsupported). // // Currently, only function references are supported. References []Reference // Min is the minimum (function) elements in this table and cannot grow to accommodate ElementSegment. Min uint32 // Max if present is the maximum (function) elements in this table, or nil if unbounded. Max *uint32 // Type is either RefTypeFuncref or RefTypeExternRef. Type RefType } // ElementInstance represents an element instance in a module. // // See https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/exec/runtime.html#element-instances type ElementInstance struct { // References holds references whose type is either RefTypeFuncref or RefTypeExternref (unsupported). References []Reference // Type is the RefType of the references in this instance's References. Type RefType } // Reference is the runtime representation of RefType which is either RefTypeFuncref or RefTypeExternref. type Reference = uintptr type GlobalType struct { ValType ValueType Mutable bool } type Global struct { Type *GlobalType Init *ConstantExpression } type ConstantExpression struct { Opcode Opcode Data []byte } // Export is the binary representation of an export indicated by Type // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-export type Export struct { Type ExternType // Name is what the host refers to this definition as. Name string // Index is the index of the definition to export, the index namespace is by Type // Ex. If ExternTypeFunc, this is a position in the function index namespace. Index Index } // Code is an entry in the Module.CodeSection containing the locals and body of the function. // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-code type Code struct { // LocalTypes are any function-scoped variables in insertion order. // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-local LocalTypes []ValueType // Body is a sequence of expressions ending in OpcodeEnd // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-expr Body []byte } type DataSegment struct { OffsetExpression *ConstantExpression Init []byte } // NameSection represent the known custom name subsections defined in the WebAssembly Binary Format // // Note: This can be nil if no names were decoded for any reason including configuration. // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#name-section%E2%91%A0 type NameSection struct { // ModuleName is the symbolic identifier for a module. Ex. math // // Note: This can be empty for any reason including configuration. ModuleName string // FunctionNames is an association of a function index to its symbolic identifier. Ex. add // // * the key (idx) is in the function namespace, where module defined functions are preceded by imported ones. // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#functions%E2%91%A7 // // Ex. Assuming the below text format is the second import, you would expect FunctionNames[1] = "mul" // (import "Math" "Mul" (func $mul (param $x f32) (param $y f32) (result f32))) // // Note: FunctionNames are only used for debugging. At runtime, functions are called based on raw numeric index. // Note: This can be nil for any reason including configuration. FunctionNames NameMap // LocalNames contains symbolic names for function parameters or locals that have one. // // Note: In the Text Format, function local names can inherit parameter names from their type. Ex. // * (module (import (func (param $x i32) (param i32))) (func (type 0))) = [{0, {x,0}}] // * (module (import (func (param i32) (param $y i32))) (func (type 0) (local $z i32))) = [0, [{y,1},{z,2}]] // * (module (func (param $x i32) (local $y i32) (local $z i32))) = [{x,0},{y,1},{z,2}] // // Note: LocalNames are only used for debugging. At runtime, locals are called based on raw numeric index. // Note: This can be nil for any reason including configuration. LocalNames IndirectNameMap } // CustomSection contains the name and raw data of a custom section. type CustomSection struct { Name string Data []byte } // NameMap associates an index with any associated names. // // Note: Often the index namespace bridges multiple sections. For example, the function index namespace starts with any // ExternTypeFunc in the Module.ImportSection followed by the Module.FunctionSection // // Note: NameMap is unique by NameAssoc.Index, but NameAssoc.Name needn't be unique. // Note: When encoding in the Binary format, this must be ordered by NameAssoc.Index // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-namemap type NameMap []*NameAssoc type NameAssoc struct { Index Index Name string } // IndirectNameMap associates an index with an association of names. // // Note: IndirectNameMap is unique by NameMapAssoc.Index, but NameMapAssoc.NameMap needn't be unique. // Note: When encoding in the Binary format, this must be ordered by NameMapAssoc.Index // https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-indirectnamemap type IndirectNameMap []*NameMapAssoc type NameMapAssoc struct { Index Index NameMap NameMap } // SectionID identifies the sections of a Module in the WebAssembly Binary Format. // // Note: these are defined in the wasm package, instead of the binary package, as a key per section is needed regardless // of format, and deferring to the binary type avoids confusion. // // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#sections%E2%91%A0 type SectionID = byte const ( // SectionIDCustom includes the standard defined NameSection and possibly others not defined in the standard. SectionIDCustom SectionID = iota // don't add anything not in https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#sections%E2%91%A0 SectionIDType SectionIDImport SectionIDFunction SectionIDTable SectionIDMemory SectionIDGlobal SectionIDExport SectionIDStart SectionIDElement SectionIDCode SectionIDData // SectionIDDataCount may exist in WebAssembly 2.0 or WebAssembly 1.0 with FeatureBulkMemoryOperations enabled. // // See https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/binary/modules.html#data-count-section // See https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/appendix/changes.html#bulk-memory-and-table-instructions SectionIDDataCount ) // SectionIDName returns the canonical name of a module section. // https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#sections%E2%91%A0 func SectionIDName(sectionID SectionID) string { switch sectionID { case SectionIDCustom: return "custom" case SectionIDType: return "type" case SectionIDImport: return "import" case SectionIDFunction: return "function" case SectionIDTable: return "table" case SectionIDMemory: return "memory" case SectionIDGlobal: return "global" case SectionIDExport: return "export" case SectionIDStart: return "start" case SectionIDElement: return "element" case SectionIDCode: return "code" case SectionIDData: return "data" case SectionIDDataCount: return "data_count" } return "unknown" }