working commit
This commit is contained in:
+86
@@ -0,0 +1,86 @@
|
||||
package wasm
|
||||
|
||||
import "fmt"
|
||||
|
||||
// ImportFuncCount returns the possibly empty count of imported functions. This plus SectionElementCount of
|
||||
// SectionIDFunction is the size of the function index namespace.
|
||||
func (m *Module) ImportFuncCount() uint32 {
|
||||
return m.importCount(ExternTypeFunc)
|
||||
}
|
||||
|
||||
// ImportTableCount returns the possibly empty count of imported tables. This plus SectionElementCount of SectionIDTable
|
||||
// is the size of the table index namespace.
|
||||
func (m *Module) ImportTableCount() uint32 {
|
||||
return m.importCount(ExternTypeTable)
|
||||
}
|
||||
|
||||
// ImportMemoryCount returns the possibly empty count of imported memories. This plus SectionElementCount of
|
||||
// SectionIDMemory is the size of the memory index namespace.
|
||||
func (m *Module) ImportMemoryCount() uint32 {
|
||||
return m.importCount(ExternTypeMemory) // TODO: once validation happens on decode, this is zero or one.
|
||||
}
|
||||
|
||||
// ImportGlobalCount returns the possibly empty count of imported globals. This plus SectionElementCount of
|
||||
// SectionIDGlobal is the size of the global index namespace.
|
||||
func (m *Module) ImportGlobalCount() uint32 {
|
||||
return m.importCount(ExternTypeGlobal)
|
||||
}
|
||||
|
||||
// importCount returns the count of a specific type of import. This is important because it is easy to mistake the
|
||||
// length of the import section with the count of a specific kind of import.
|
||||
func (m *Module) importCount(et ExternType) (res uint32) {
|
||||
for _, im := range m.ImportSection {
|
||||
if im.Type == et {
|
||||
res++
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// SectionElementCount returns the count of elements in a given section ID
|
||||
//
|
||||
// For example...
|
||||
// * SectionIDType returns the count of FunctionType
|
||||
// * SectionIDCustom returns one if the NameSection is present
|
||||
// * SectionIDHostFunction returns the count of HostFunctionSection
|
||||
// * SectionIDExport returns the count of unique export names
|
||||
func (m *Module) SectionElementCount(sectionID SectionID) uint32 { // element as in vector elements!
|
||||
switch sectionID {
|
||||
case SectionIDCustom:
|
||||
numCustomSections := uint32(len(m.CustomSections))
|
||||
if m.NameSection != nil {
|
||||
numCustomSections++
|
||||
}
|
||||
return numCustomSections
|
||||
case SectionIDType:
|
||||
return uint32(len(m.TypeSection))
|
||||
case SectionIDImport:
|
||||
return uint32(len(m.ImportSection))
|
||||
case SectionIDFunction:
|
||||
return uint32(len(m.FunctionSection))
|
||||
case SectionIDTable:
|
||||
return uint32(len(m.TableSection))
|
||||
case SectionIDMemory:
|
||||
if m.MemorySection != nil {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
case SectionIDGlobal:
|
||||
return uint32(len(m.GlobalSection))
|
||||
case SectionIDExport:
|
||||
return uint32(len(m.ExportSection))
|
||||
case SectionIDStart:
|
||||
if m.StartSection != nil {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
case SectionIDElement:
|
||||
return uint32(len(m.ElementSection))
|
||||
case SectionIDCode:
|
||||
return uint32(len(m.CodeSection))
|
||||
case SectionIDData:
|
||||
return uint32(len(m.DataSection))
|
||||
default:
|
||||
panic(fmt.Errorf("BUG: unknown section: %d", sectionID))
|
||||
}
|
||||
}
|
||||
+212
@@ -0,0 +1,212 @@
|
||||
package wasm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// CoreFeatures is a bit flag of WebAssembly Core specification features. See
|
||||
// https://github.com/WebAssembly/proposals for proposals and their status.
|
||||
//
|
||||
// Constants define individual features, such as CoreFeatureMultiValue, or
|
||||
// groups of "finished" features, assigned to a WebAssembly Core Specification
|
||||
// version, ex. CoreFeaturesV1 or CoreFeaturesV2.
|
||||
//
|
||||
// Note: Numeric values are not intended to be interpreted except as bit flags.
|
||||
type CoreFeatures uint64
|
||||
|
||||
// CoreFeaturesV1 are features included in the WebAssembly Core Specification
|
||||
// 1.0. As of late 2022, this is the only version that is a Web Standard (W3C
|
||||
// Recommendation).
|
||||
//
|
||||
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/
|
||||
const CoreFeaturesV1 = CoreFeatureMutableGlobal
|
||||
|
||||
// CoreFeaturesV2 are features included in the WebAssembly Core Specification
|
||||
// 2.0 (20220419). As of late 2022, version 2.0 is a W3C working draft, not yet
|
||||
// a Web Standard (W3C Recommendation).
|
||||
//
|
||||
// See https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/appendix/changes.html#release-1-1
|
||||
const CoreFeaturesV2 = CoreFeaturesV1 |
|
||||
CoreFeatureBulkMemoryOperations |
|
||||
CoreFeatureMultiValue |
|
||||
CoreFeatureNonTrappingFloatToIntConversion |
|
||||
CoreFeatureReferenceTypes |
|
||||
CoreFeatureSignExtensionOps |
|
||||
CoreFeatureSIMD
|
||||
|
||||
const (
|
||||
// CoreFeatureBulkMemoryOperations adds instructions modify ranges of
|
||||
// memory or table entries ("bulk-memory-operations"). This is included in
|
||||
// CoreFeaturesV2, but not CoreFeaturesV1.
|
||||
//
|
||||
// Here are the notable effects:
|
||||
// - Adds `memory.fill`, `memory.init`, `memory.copy` and `data.drop`
|
||||
// instructions.
|
||||
// - Adds `table.init`, `table.copy` and `elem.drop` instructions.
|
||||
// - Introduces a "passive" form of element and data segments.
|
||||
// - Stops checking "active" element and data segment boundaries at
|
||||
// compile-time, meaning they can error at runtime.
|
||||
//
|
||||
// Note: "bulk-memory-operations" is mixed with the "reference-types"
|
||||
// proposal due to the WebAssembly Working Group merging them
|
||||
// "mutually dependent". Therefore, enabling this feature requires enabling
|
||||
// CoreFeatureReferenceTypes, and vice-versa.
|
||||
//
|
||||
// See https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/bulk-memory-operations/Overview.md
|
||||
// https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/reference-types/Overview.md and
|
||||
// https://github.com/WebAssembly/spec/pull/1287
|
||||
CoreFeatureBulkMemoryOperations CoreFeatures = 1 << iota
|
||||
|
||||
// CoreFeatureMultiValue enables multiple values ("multi-value"). This is
|
||||
// included in CoreFeaturesV2, but not CoreFeaturesV1.
|
||||
//
|
||||
// Here are the notable effects:
|
||||
// - Function (`func`) types allow more than one result.
|
||||
// - Block types (`block`, `loop` and `if`) can be arbitrary function
|
||||
// types.
|
||||
//
|
||||
// See https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/multi-value/Overview.md
|
||||
CoreFeatureMultiValue
|
||||
|
||||
// CoreFeatureMutableGlobal allows globals to be mutable. This is included
|
||||
// in both CoreFeaturesV1 and CoreFeaturesV2.
|
||||
//
|
||||
// When false, an api.Global can never be cast to an api.MutableGlobal, and
|
||||
// any wasm that includes global vars will fail to parse.
|
||||
CoreFeatureMutableGlobal
|
||||
|
||||
// CoreFeatureNonTrappingFloatToIntConversion enables non-trapping
|
||||
// float-to-int conversions ("nontrapping-float-to-int-conversion"). This
|
||||
// is included in CoreFeaturesV2, but not CoreFeaturesV1.
|
||||
//
|
||||
// The only effect of enabling is allowing the following instructions,
|
||||
// which return 0 on NaN instead of panicking.
|
||||
// - `i32.trunc_sat_f32_s`
|
||||
// - `i32.trunc_sat_f32_u`
|
||||
// - `i32.trunc_sat_f64_s`
|
||||
// - `i32.trunc_sat_f64_u`
|
||||
// - `i64.trunc_sat_f32_s`
|
||||
// - `i64.trunc_sat_f32_u`
|
||||
// - `i64.trunc_sat_f64_s`
|
||||
// - `i64.trunc_sat_f64_u`
|
||||
//
|
||||
// See https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/nontrapping-float-to-int-conversion/Overview.md
|
||||
CoreFeatureNonTrappingFloatToIntConversion
|
||||
|
||||
// CoreFeatureReferenceTypes enables various instructions and features
|
||||
// related to table and new reference types. This is included in
|
||||
// CoreFeaturesV2, but not CoreFeaturesV1.
|
||||
//
|
||||
// - Introduction of new value types: `funcref` and `externref`.
|
||||
// - Support for the following new instructions:
|
||||
// - `ref.null`
|
||||
// - `ref.func`
|
||||
// - `ref.is_null`
|
||||
// - `table.fill`
|
||||
// - `table.get`
|
||||
// - `table.grow`
|
||||
// - `table.set`
|
||||
// - `table.size`
|
||||
// - Support for multiple tables per module:
|
||||
// - `call_indirect`, `table.init`, `table.copy` and `elem.drop`
|
||||
// - Support for instructions can take non-zero table index.
|
||||
// - Element segments can take non-zero table index.
|
||||
//
|
||||
// Note: "reference-types" is mixed with the "bulk-memory-operations"
|
||||
// proposal due to the WebAssembly Working Group merging them
|
||||
// "mutually dependent". Therefore, enabling this feature requires enabling
|
||||
// CoreFeatureBulkMemoryOperations, and vice-versa.
|
||||
//
|
||||
// See https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/bulk-memory-operations/Overview.md
|
||||
// https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/reference-types/Overview.md and
|
||||
// https://github.com/WebAssembly/spec/pull/1287
|
||||
CoreFeatureReferenceTypes
|
||||
|
||||
// CoreFeatureSignExtensionOps enables sign extension instructions
|
||||
// ("sign-extension-ops"). This is included in CoreFeaturesV2, but not
|
||||
// CoreFeaturesV1.
|
||||
//
|
||||
// Adds instructions:
|
||||
// - `i32.extend8_s`
|
||||
// - `i32.extend16_s`
|
||||
// - `i64.extend8_s`
|
||||
// - `i64.extend16_s`
|
||||
// - `i64.extend32_s`
|
||||
//
|
||||
// See https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/sign-extension-ops/Overview.md
|
||||
CoreFeatureSignExtensionOps
|
||||
|
||||
// CoreFeatureSIMD enables the vector value type and vector instructions
|
||||
// (aka SIMD). This is included in CoreFeaturesV2, but not CoreFeaturesV1.
|
||||
//
|
||||
// Note: The instruction list is too long to enumerate in godoc.
|
||||
// See https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/simd/SIMD.md
|
||||
CoreFeatureSIMD
|
||||
)
|
||||
|
||||
// SetEnabled enables or disables the feature or group of features.
|
||||
func (f CoreFeatures) SetEnabled(feature CoreFeatures, val bool) CoreFeatures {
|
||||
if val {
|
||||
return f | feature
|
||||
}
|
||||
return f &^ feature
|
||||
}
|
||||
|
||||
// IsEnabled returns true if the feature (or group of features) is enabled.
|
||||
func (f CoreFeatures) IsEnabled(feature CoreFeatures) bool {
|
||||
return f&feature != 0
|
||||
}
|
||||
|
||||
// RequireEnabled returns an error if the feature (or group of features) is not
|
||||
// enabled.
|
||||
func (f CoreFeatures) RequireEnabled(feature CoreFeatures) error {
|
||||
if f&feature == 0 {
|
||||
return fmt.Errorf("feature %q is disabled", feature)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// String implements fmt.Stringer by returning each enabled feature.
|
||||
func (f CoreFeatures) String() string {
|
||||
var builder strings.Builder
|
||||
for i := 0; i <= 63; i++ { // cycle through all bits to reduce code and maintenance
|
||||
target := CoreFeatures(1 << i)
|
||||
if f.IsEnabled(target) {
|
||||
if name := featureName(target); name != "" {
|
||||
if builder.Len() > 0 {
|
||||
builder.WriteByte('|')
|
||||
}
|
||||
builder.WriteString(name)
|
||||
}
|
||||
}
|
||||
}
|
||||
return builder.String()
|
||||
}
|
||||
|
||||
func featureName(f CoreFeatures) string {
|
||||
switch f {
|
||||
case CoreFeatureMutableGlobal:
|
||||
// match https://github.com/WebAssembly/mutable-global
|
||||
return "mutable-global"
|
||||
case CoreFeatureSignExtensionOps:
|
||||
// match https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/sign-extension-ops/Overview.md
|
||||
return "sign-extension-ops"
|
||||
case CoreFeatureMultiValue:
|
||||
// match https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/multi-value/Overview.md
|
||||
return "multi-value"
|
||||
case CoreFeatureNonTrappingFloatToIntConversion:
|
||||
// match https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/nontrapping-float-to-int-conversion/Overview.md
|
||||
return "nontrapping-float-to-int-conversion"
|
||||
case CoreFeatureBulkMemoryOperations:
|
||||
// match https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/bulk-memory-operations/Overview.md
|
||||
return "bulk-memory-operations"
|
||||
case CoreFeatureReferenceTypes:
|
||||
// match https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/reference-types/Overview.md
|
||||
return "reference-types"
|
||||
case CoreFeatureSIMD:
|
||||
// match https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/simd/SIMD.md
|
||||
return "simd"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
+1550
File diff suppressed because it is too large
Load Diff
+45
@@ -0,0 +1,45 @@
|
||||
package wasm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
const (
|
||||
// MemoryPageSize is the unit of memory length in WebAssembly,
|
||||
// and is defined as 2^16 = 65536.
|
||||
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#memory-instances%E2%91%A0
|
||||
MemoryPageSize = uint32(65536)
|
||||
// MemoryPageSizeInBits satisfies the relation: "1 << MemoryPageSizeInBits == MemoryPageSize".
|
||||
MemoryPageSizeInBits = 16
|
||||
)
|
||||
|
||||
// MemoryPagesToBytesNum converts the given pages into the number of bytes contained in these pages.
|
||||
func MemoryPagesToBytesNum(pages uint32) (bytesNum uint64) {
|
||||
return uint64(pages) << MemoryPageSizeInBits
|
||||
}
|
||||
|
||||
// PagesToUnitOfBytes converts the pages to a human-readable form similar to what's specified. Ex. 1 -> "64Ki"
|
||||
//
|
||||
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#memory-instances%E2%91%A0
|
||||
func PagesToUnitOfBytes(pages uint32) string {
|
||||
k := pages * 64
|
||||
if k < 1024 {
|
||||
return fmt.Sprintf("%d Ki", k)
|
||||
}
|
||||
m := k / 1024
|
||||
if m < 1024 {
|
||||
return fmt.Sprintf("%d Mi", m)
|
||||
}
|
||||
g := m / 1024
|
||||
if g < 1024 {
|
||||
return fmt.Sprintf("%d Gi", g)
|
||||
}
|
||||
return fmt.Sprintf("%d Ti", g/1024)
|
||||
}
|
||||
|
||||
// Below are raw functions used to implement the api.Memory API:
|
||||
|
||||
// memoryBytesNumToPages converts the given number of bytes into the number of pages.
|
||||
func memoryBytesNumToPages(bytesNum uint64) (pages uint32) {
|
||||
return uint32(bytesNum >> MemoryPageSizeInBits)
|
||||
}
|
||||
+496
@@ -0,0 +1,496 @@
|
||||
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"
|
||||
}
|
||||
+180
@@ -0,0 +1,180 @@
|
||||
package wasm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
||||
|
||||
// ValueType describes a numeric type used in Web Assembly 1.0 (20191205). For example, Function parameters and results are
|
||||
// only definable as a value type.
|
||||
//
|
||||
// The following describes how to convert between Wasm and Golang types:
|
||||
//
|
||||
// - ValueTypeI32 - uint64(uint32,int32)
|
||||
// - ValueTypeI64 - uint64(int64)
|
||||
// - ValueTypeF32 - EncodeF32 DecodeF32 from float32
|
||||
// - ValueTypeF64 - EncodeF64 DecodeF64 from float64
|
||||
// - ValueTypeExternref - uintptr(unsafe.Pointer(p)) where p is any pointer type in Go (e.g. *string)
|
||||
//
|
||||
// Ex. Given a Text Format type use (param i64) (result i64), no conversion is necessary.
|
||||
//
|
||||
// results, _ := fn(ctx, input)
|
||||
// result := result[0]
|
||||
//
|
||||
// Ex. Given a Text Format type use (param f64) (result f64), conversion is necessary.
|
||||
//
|
||||
// results, _ := fn(ctx, api.EncodeF64(input))
|
||||
// result := api.DecodeF64(result[0])
|
||||
//
|
||||
// Note: This is a type alias as it is easier to encode and decode in the binary format.
|
||||
//
|
||||
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#binary-valtype
|
||||
type ValueType = byte
|
||||
|
||||
const (
|
||||
// ValueTypeI32 is a 32-bit integer.
|
||||
ValueTypeI32 ValueType = 0x7f
|
||||
// ValueTypeI64 is a 64-bit integer.
|
||||
ValueTypeI64 ValueType = 0x7e
|
||||
// ValueTypeF32 is a 32-bit floating point number.
|
||||
ValueTypeF32 ValueType = 0x7d
|
||||
// ValueTypeF64 is a 64-bit floating point number.
|
||||
ValueTypeF64 ValueType = 0x7c
|
||||
|
||||
// ValueTypeExternref is an externref type.
|
||||
//
|
||||
// Note: in wazero, externref type value are opaque raw 64-bit pointers,
|
||||
// and the ValueTypeExternref type in the signature will be translated as
|
||||
// uintptr in wazero's API level.
|
||||
//
|
||||
// For example, given the import function:
|
||||
// (func (import "env" "f") (param externref) (result externref))
|
||||
//
|
||||
// This can be defined in Go as:
|
||||
// r.NewModuleBuilder("env").ExportFunctions(map[string]interface{}{
|
||||
// "f": func(externref uintptr) (resultExternRef uintptr) { return },
|
||||
// })
|
||||
//
|
||||
// Note: The usage of this type is toggled with WithFeatureBulkMemoryOperations.
|
||||
ValueTypeExternref ValueType = 0x6f
|
||||
|
||||
ValueTypeV128 ValueType = 0x7b
|
||||
ValueTypeFuncref ValueType = 0x70
|
||||
)
|
||||
|
||||
// ValueTypeName returns the type name of the given ValueType as a string.
|
||||
// These type names match the names used in the WebAssembly text format.
|
||||
//
|
||||
// Note: This returns "unknown", if an undefined ValueType value is passed.
|
||||
func ValueTypeName(t ValueType) string {
|
||||
switch t {
|
||||
case ValueTypeI32:
|
||||
return "i32"
|
||||
case ValueTypeI64:
|
||||
return "i64"
|
||||
case ValueTypeF32:
|
||||
return "f32"
|
||||
case ValueTypeF64:
|
||||
return "f64"
|
||||
case ValueTypeExternref:
|
||||
return "externref"
|
||||
case ValueTypeFuncref:
|
||||
return "funcref"
|
||||
case ValueTypeV128:
|
||||
return "v128"
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
// ExternType classifies imports and exports with their respective types.
|
||||
//
|
||||
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#external-types%E2%91%A0
|
||||
type ExternType = byte
|
||||
|
||||
const (
|
||||
ExternTypeFunc ExternType = 0x00
|
||||
ExternTypeTable ExternType = 0x01
|
||||
ExternTypeMemory ExternType = 0x02
|
||||
ExternTypeGlobal ExternType = 0x03
|
||||
)
|
||||
|
||||
// The below are exported to consolidate parsing behavior for external types.
|
||||
const (
|
||||
// ExternTypeFuncName is the name of the WebAssembly Text Format field for ExternTypeFunc.
|
||||
ExternTypeFuncName = "func"
|
||||
// ExternTypeTableName is the name of the WebAssembly Text Format field for ExternTypeTable.
|
||||
ExternTypeTableName = "table"
|
||||
// ExternTypeMemoryName is the name of the WebAssembly Text Format field for ExternTypeMemory.
|
||||
ExternTypeMemoryName = "memory"
|
||||
// ExternTypeGlobalName is the name of the WebAssembly Text Format field for ExternTypeGlobal.
|
||||
ExternTypeGlobalName = "global"
|
||||
)
|
||||
|
||||
// ExternTypeName returns the name of the WebAssembly Text Format field of the given type.
|
||||
//
|
||||
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#exports%E2%91%A4
|
||||
func ExternTypeName(et ExternType) string {
|
||||
switch et {
|
||||
case ExternTypeFunc:
|
||||
return ExternTypeFuncName
|
||||
case ExternTypeTable:
|
||||
return ExternTypeTableName
|
||||
case ExternTypeMemory:
|
||||
return ExternTypeMemoryName
|
||||
case ExternTypeGlobal:
|
||||
return ExternTypeGlobalName
|
||||
}
|
||||
return fmt.Sprintf("%#x", et)
|
||||
}
|
||||
|
||||
// EncodeI32 encodes the input as a ValueTypeI32.
|
||||
func EncodeI32(input int32) uint64 {
|
||||
return uint64(uint32(input))
|
||||
}
|
||||
|
||||
// EncodeI64 encodes the input as a ValueTypeI64.
|
||||
func EncodeI64(input int64) uint64 {
|
||||
return uint64(input)
|
||||
}
|
||||
|
||||
// EncodeF32 encodes the input as a ValueTypeF32.
|
||||
//
|
||||
// See DecodeF32
|
||||
func EncodeF32(input float32) uint64 {
|
||||
return uint64(math.Float32bits(input))
|
||||
}
|
||||
|
||||
// DecodeF32 decodes the input as a ValueTypeF32.
|
||||
//
|
||||
// See EncodeF32
|
||||
func DecodeF32(input uint64) float32 {
|
||||
return math.Float32frombits(uint32(input))
|
||||
}
|
||||
|
||||
// EncodeF64 encodes the input as a ValueTypeF64.
|
||||
//
|
||||
// See EncodeF32
|
||||
func EncodeF64(input float64) uint64 {
|
||||
return math.Float64bits(input)
|
||||
}
|
||||
|
||||
// DecodeF64 decodes the input as a ValueTypeF64.
|
||||
//
|
||||
// See EncodeF64
|
||||
func DecodeF64(input uint64) float64 {
|
||||
return math.Float64frombits(input)
|
||||
}
|
||||
|
||||
// EncodeExternref encodes the input as a ValueTypeExternref.
|
||||
//
|
||||
// See DecodeExternref
|
||||
func EncodeExternref(input uintptr) uint64 {
|
||||
return uint64(input)
|
||||
}
|
||||
|
||||
// DecodeExternref decodes the input as a ValueTypeExternref.
|
||||
//
|
||||
// See EncodeExternref
|
||||
func DecodeExternref(input uint64) uintptr {
|
||||
return uintptr(input)
|
||||
}
|
||||
Reference in New Issue
Block a user