working commit
This commit is contained in:
+342
@@ -0,0 +1,342 @@
|
||||
package binary
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/tetratelabs/wabin/leb128"
|
||||
"github.com/tetratelabs/wabin/wasm"
|
||||
)
|
||||
|
||||
func decodeTypeSection(features wasm.CoreFeatures, r *bytes.Reader) ([]*wasm.FunctionType, error) {
|
||||
vs, _, err := leb128.DecodeUint32(r)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get size of vector: %w", err)
|
||||
}
|
||||
|
||||
result := make([]*wasm.FunctionType, vs)
|
||||
for i := uint32(0); i < vs; i++ {
|
||||
if result[i], err = decodeFunctionType(features, r); err != nil {
|
||||
return nil, fmt.Errorf("read %d-th type: %v", i, err)
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func decodeImportSection(r *bytes.Reader, features wasm.CoreFeatures) ([]*wasm.Import, error) {
|
||||
vs, _, err := leb128.DecodeUint32(r)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get size of vector: %w", err)
|
||||
}
|
||||
|
||||
result := make([]*wasm.Import, vs)
|
||||
for i := uint32(0); i < vs; i++ {
|
||||
if result[i], err = decodeImport(r, i, features); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func decodeFunctionSection(r *bytes.Reader) ([]uint32, error) {
|
||||
vs, _, err := leb128.DecodeUint32(r)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get size of vector: %w", err)
|
||||
}
|
||||
|
||||
result := make([]uint32, vs)
|
||||
for i := uint32(0); i < vs; i++ {
|
||||
if result[i], _, err = leb128.DecodeUint32(r); err != nil {
|
||||
return nil, fmt.Errorf("get type index: %w", err)
|
||||
}
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func decodeTableSection(r *bytes.Reader, features wasm.CoreFeatures) ([]*wasm.Table, error) {
|
||||
vs, _, err := leb128.DecodeUint32(r)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading size")
|
||||
}
|
||||
if vs > 1 {
|
||||
if err := features.RequireEnabled(wasm.CoreFeatureReferenceTypes); err != nil {
|
||||
return nil, fmt.Errorf("at most one table allowed in module as %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
ret := make([]*wasm.Table, vs)
|
||||
for i := range ret {
|
||||
table, err := decodeTable(r, features)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret[i] = table
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func decodeMemorySection(r *bytes.Reader) (*wasm.Memory, error) {
|
||||
vs, _, err := leb128.DecodeUint32(r)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading size")
|
||||
}
|
||||
if vs > 1 {
|
||||
return nil, fmt.Errorf("at most one memory allowed in module, but read %d", vs)
|
||||
}
|
||||
|
||||
return decodeMemory(r)
|
||||
}
|
||||
|
||||
func decodeGlobalSection(r *bytes.Reader, features wasm.CoreFeatures) ([]*wasm.Global, error) {
|
||||
vs, _, err := leb128.DecodeUint32(r)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get size of vector: %w", err)
|
||||
}
|
||||
|
||||
result := make([]*wasm.Global, vs)
|
||||
for i := uint32(0); i < vs; i++ {
|
||||
if result[i], err = decodeGlobal(r, features); err != nil {
|
||||
return nil, fmt.Errorf("global[%d]: %w", i, err)
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func decodeExportSection(r *bytes.Reader) ([]*wasm.Export, error) {
|
||||
vs, _, sizeErr := leb128.DecodeUint32(r)
|
||||
if sizeErr != nil {
|
||||
return nil, fmt.Errorf("get size of vector: %v", sizeErr)
|
||||
}
|
||||
|
||||
usedName := make(map[string]struct{}, vs)
|
||||
exportSection := make([]*wasm.Export, 0, vs)
|
||||
for i := wasm.Index(0); i < vs; i++ {
|
||||
export, err := decodeExport(r)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read export: %w", err)
|
||||
}
|
||||
if _, ok := usedName[export.Name]; ok {
|
||||
return nil, fmt.Errorf("export[%d] duplicates name %q", i, export.Name)
|
||||
} else {
|
||||
usedName[export.Name] = struct{}{}
|
||||
}
|
||||
exportSection = append(exportSection, export)
|
||||
}
|
||||
return exportSection, nil
|
||||
}
|
||||
|
||||
func decodeStartSection(r *bytes.Reader) (*wasm.Index, error) {
|
||||
vs, _, err := leb128.DecodeUint32(r)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get function index: %w", err)
|
||||
}
|
||||
return &vs, nil
|
||||
}
|
||||
|
||||
func decodeElementSection(r *bytes.Reader, features wasm.CoreFeatures) ([]*wasm.ElementSegment, error) {
|
||||
vs, _, err := leb128.DecodeUint32(r)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get size of vector: %w", err)
|
||||
}
|
||||
|
||||
result := make([]*wasm.ElementSegment, vs)
|
||||
for i := uint32(0); i < vs; i++ {
|
||||
if result[i], err = decodeElementSegment(r, features); err != nil {
|
||||
return nil, fmt.Errorf("read element: %w", err)
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func decodeCodeSection(r *bytes.Reader) ([]*wasm.Code, error) {
|
||||
vs, _, err := leb128.DecodeUint32(r)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get size of vector: %w", err)
|
||||
}
|
||||
|
||||
result := make([]*wasm.Code, vs)
|
||||
for i := uint32(0); i < vs; i++ {
|
||||
if result[i], err = decodeCode(r); err != nil {
|
||||
return nil, fmt.Errorf("read %d-th code segment: %v", i, err)
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func decodeDataSection(r *bytes.Reader, features wasm.CoreFeatures) ([]*wasm.DataSegment, error) {
|
||||
vs, _, err := leb128.DecodeUint32(r)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get size of vector: %w", err)
|
||||
}
|
||||
|
||||
result := make([]*wasm.DataSegment, vs)
|
||||
for i := uint32(0); i < vs; i++ {
|
||||
if result[i], err = decodeDataSegment(r, features); err != nil {
|
||||
return nil, fmt.Errorf("read data segment: %w", err)
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func decodeDataCountSection(r *bytes.Reader) (count *uint32, err error) {
|
||||
v, _, err := leb128.DecodeUint32(r)
|
||||
if err != nil && err != io.EOF {
|
||||
// data count is optional, so EOF is fine.
|
||||
return nil, err
|
||||
}
|
||||
return &v, nil
|
||||
}
|
||||
|
||||
// encodeSection encodes the sectionID, the size of its contents in bytes,
|
||||
// followed by the contents.
|
||||
//
|
||||
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#sections%E2%91%A0
|
||||
func encodeSection(sectionID wasm.SectionID, contents []byte) []byte {
|
||||
return append([]byte{sectionID}, encodeSizePrefixed(contents)...)
|
||||
}
|
||||
|
||||
// encodeTypeSection encodes a wasm.SectionIDType for the given imports in
|
||||
// WebAssembly Binary Format.
|
||||
//
|
||||
// See encodeFunctionType
|
||||
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#type-section%E2%91%A0
|
||||
func encodeTypeSection(types []*wasm.FunctionType) []byte {
|
||||
contents := leb128.EncodeUint32(uint32(len(types)))
|
||||
for _, t := range types {
|
||||
contents = append(contents, encodeFunctionType(t)...)
|
||||
}
|
||||
return encodeSection(wasm.SectionIDType, contents)
|
||||
}
|
||||
|
||||
// encodeImportSection encodes a wasm.SectionIDImport for the given imports in
|
||||
// WebAssembly Binary Format.
|
||||
//
|
||||
// See encodeImport
|
||||
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#import-section%E2%91%A0
|
||||
func encodeImportSection(imports []*wasm.Import) []byte {
|
||||
contents := leb128.EncodeUint32(uint32(len(imports)))
|
||||
for _, i := range imports {
|
||||
contents = append(contents, encodeImport(i)...)
|
||||
}
|
||||
return encodeSection(wasm.SectionIDImport, contents)
|
||||
}
|
||||
|
||||
// encodeFunctionSection encodes a wasm.SectionIDFunction for the type indices
|
||||
// associated with module-defined functions in WebAssembly Binary Format.
|
||||
//
|
||||
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#function-section%E2%91%A0
|
||||
func encodeFunctionSection(typeIndices []wasm.Index) []byte {
|
||||
contents := leb128.EncodeUint32(uint32(len(typeIndices)))
|
||||
for _, index := range typeIndices {
|
||||
contents = append(contents, leb128.EncodeUint32(index)...)
|
||||
}
|
||||
return encodeSection(wasm.SectionIDFunction, contents)
|
||||
}
|
||||
|
||||
// encodeCodeSection encodes a wasm.SectionIDCode for the module-defined
|
||||
// function in WebAssembly Binary Format.
|
||||
//
|
||||
// See encodeCode
|
||||
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#code-section%E2%91%A0
|
||||
func encodeCodeSection(code []*wasm.Code) []byte {
|
||||
contents := leb128.EncodeUint32(uint32(len(code)))
|
||||
for _, i := range code {
|
||||
contents = append(contents, encodeCode(i)...)
|
||||
}
|
||||
return encodeSection(wasm.SectionIDCode, contents)
|
||||
}
|
||||
|
||||
// encodeTableSection encodes a wasm.SectionIDTable for the module-defined
|
||||
// function in WebAssembly Binary Format.
|
||||
//
|
||||
// See encodeTable
|
||||
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#table-section%E2%91%A0
|
||||
func encodeTableSection(tables []*wasm.Table) []byte {
|
||||
var contents = leb128.EncodeUint32(uint32(len(tables)))
|
||||
for _, table := range tables {
|
||||
contents = append(contents, encodeTable(table)...)
|
||||
}
|
||||
return encodeSection(wasm.SectionIDTable, contents)
|
||||
}
|
||||
|
||||
// encodeMemorySection encodes a wasm.SectionIDMemory for the module-defined
|
||||
// function in WebAssembly Binary Format.
|
||||
//
|
||||
// See encodeMemory
|
||||
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#memory-section%E2%91%A0
|
||||
func encodeMemorySection(memory *wasm.Memory) []byte {
|
||||
contents := append([]byte{1}, encodeMemory(memory)...)
|
||||
return encodeSection(wasm.SectionIDMemory, contents)
|
||||
}
|
||||
|
||||
// encodeGlobalSection encodes a wasm.SectionIDGlobal for the given globals in
|
||||
// WebAssembly Binary Format.
|
||||
//
|
||||
// See encodeGlobal
|
||||
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#global-section%E2%91%A0
|
||||
func encodeGlobalSection(globals []*wasm.Global) []byte {
|
||||
contents := leb128.EncodeUint32(uint32(len(globals)))
|
||||
for _, g := range globals {
|
||||
contents = append(contents, encodeGlobal(g)...)
|
||||
}
|
||||
return encodeSection(wasm.SectionIDGlobal, contents)
|
||||
}
|
||||
|
||||
// encodeExportSection encodes a wasm.SectionIDExport for the given exports in
|
||||
// WebAssembly Binary Format.
|
||||
//
|
||||
// See encodeExport
|
||||
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#export-section%E2%91%A0
|
||||
func encodeExportSection(exports []*wasm.Export) []byte {
|
||||
contents := leb128.EncodeUint32(uint32(len(exports)))
|
||||
for _, e := range exports {
|
||||
contents = append(contents, encodeExport(e)...)
|
||||
}
|
||||
return encodeSection(wasm.SectionIDExport, contents)
|
||||
}
|
||||
|
||||
// encodeStartSection encodes a wasm.SectionIDStart for the given function
|
||||
// index in WebAssembly Binary Format.
|
||||
//
|
||||
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#start-section%E2%91%A0
|
||||
func encodeStartSection(funcidx wasm.Index) []byte {
|
||||
return encodeSection(wasm.SectionIDStart, leb128.EncodeUint32(funcidx))
|
||||
}
|
||||
|
||||
// encodeElementSection encodes a wasm.SectionIDElement for the elements in
|
||||
// WebAssembly Binary Format.
|
||||
//
|
||||
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#element-section%E2%91%A0
|
||||
func encodeElementSection(elements []*wasm.ElementSegment) []byte {
|
||||
contents := leb128.EncodeUint32(uint32(len(elements)))
|
||||
for _, e := range elements {
|
||||
contents = append(contents, encodeElement(e)...)
|
||||
}
|
||||
return encodeSection(wasm.SectionIDElement, contents)
|
||||
}
|
||||
|
||||
// encodeDataSection encodes a wasm.SectionIDData for the data in WebAssembly 1.0 (20191205)
|
||||
// Binary Format.
|
||||
//
|
||||
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#data-section%E2%91%A0
|
||||
func encodeDataSection(datum []*wasm.DataSegment) []byte {
|
||||
contents := leb128.EncodeUint32(uint32(len(datum)))
|
||||
for _, d := range datum {
|
||||
contents = append(contents, encodeDataSegment(d)...)
|
||||
}
|
||||
return encodeSection(wasm.SectionIDData, contents)
|
||||
}
|
||||
|
||||
// encodeCustomSection encodes a wasm.SectionIDCustom for the data in WebAssembly 1.0 (20191205)
|
||||
// Binary Format. This is used for custom sections that are **not** associated with the "name" key.
|
||||
//
|
||||
// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#custom-section%E2%91%A0
|
||||
func encodeCustomSection(c *wasm.CustomSection) (data []byte) {
|
||||
data = make([]byte, 0, 1+len(c.Name)+len(c.Data))
|
||||
l := byte(len(c.Name))
|
||||
data = append(data, l)
|
||||
data = append(data, []byte(c.Name)...)
|
||||
data = append(data, c.Data...)
|
||||
return
|
||||
}
|
||||
Reference in New Issue
Block a user