wa-lang.org/wazero@v1.0.2/internal/wasm/binary/section.go (about)

     1  package binary
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io"
     7  
     8  	"wa-lang.org/wazero/api"
     9  	"wa-lang.org/wazero/internal/leb128"
    10  	"wa-lang.org/wazero/internal/wasm"
    11  )
    12  
    13  func decodeTypeSection(enabledFeatures api.CoreFeatures, r *bytes.Reader) ([]*wasm.FunctionType, error) {
    14  	vs, _, err := leb128.DecodeUint32(r)
    15  	if err != nil {
    16  		return nil, fmt.Errorf("get size of vector: %w", err)
    17  	}
    18  
    19  	result := make([]*wasm.FunctionType, vs)
    20  	for i := uint32(0); i < vs; i++ {
    21  		if result[i], err = decodeFunctionType(enabledFeatures, r); err != nil {
    22  			return nil, fmt.Errorf("read %d-th type: %v", i, err)
    23  		}
    24  	}
    25  	return result, nil
    26  }
    27  
    28  func decodeImportSection(
    29  	r *bytes.Reader,
    30  	memorySizer func(minPages uint32, maxPages *uint32) (min, capacity, max uint32),
    31  	memoryLimitPages uint32,
    32  	enabledFeatures api.CoreFeatures,
    33  ) ([]*wasm.Import, error) {
    34  	vs, _, err := leb128.DecodeUint32(r)
    35  	if err != nil {
    36  		return nil, fmt.Errorf("get size of vector: %w", err)
    37  	}
    38  
    39  	result := make([]*wasm.Import, vs)
    40  	for i := uint32(0); i < vs; i++ {
    41  		if result[i], err = decodeImport(r, i, memorySizer, memoryLimitPages, enabledFeatures); err != nil {
    42  			return nil, err
    43  		}
    44  	}
    45  	return result, nil
    46  }
    47  
    48  func decodeFunctionSection(r *bytes.Reader) ([]uint32, error) {
    49  	vs, _, err := leb128.DecodeUint32(r)
    50  	if err != nil {
    51  		return nil, fmt.Errorf("get size of vector: %w", err)
    52  	}
    53  
    54  	result := make([]uint32, vs)
    55  	for i := uint32(0); i < vs; i++ {
    56  		if result[i], _, err = leb128.DecodeUint32(r); err != nil {
    57  			return nil, fmt.Errorf("get type index: %w", err)
    58  		}
    59  	}
    60  	return result, err
    61  }
    62  
    63  func decodeTableSection(r *bytes.Reader, enabledFeatures api.CoreFeatures) ([]*wasm.Table, error) {
    64  	vs, _, err := leb128.DecodeUint32(r)
    65  	if err != nil {
    66  		return nil, fmt.Errorf("error reading size")
    67  	}
    68  	if vs > 1 {
    69  		if err := enabledFeatures.RequireEnabled(api.CoreFeatureReferenceTypes); err != nil {
    70  			return nil, fmt.Errorf("at most one table allowed in module as %w", err)
    71  		}
    72  	}
    73  
    74  	ret := make([]*wasm.Table, vs)
    75  	for i := range ret {
    76  		table, err := decodeTable(r, enabledFeatures)
    77  		if err != nil {
    78  			return nil, err
    79  		}
    80  		ret[i] = table
    81  	}
    82  	return ret, nil
    83  }
    84  
    85  func decodeMemorySection(
    86  	r *bytes.Reader,
    87  	memorySizer func(minPages uint32, maxPages *uint32) (min, capacity, max uint32),
    88  	memoryLimitPages uint32,
    89  ) (*wasm.Memory, error) {
    90  	vs, _, err := leb128.DecodeUint32(r)
    91  	if err != nil {
    92  		return nil, fmt.Errorf("error reading size")
    93  	}
    94  	if vs > 1 {
    95  		return nil, fmt.Errorf("at most one memory allowed in module, but read %d", vs)
    96  	} else if vs == 0 {
    97  		// memory count can be zero.
    98  		return nil, nil
    99  	}
   100  
   101  	return decodeMemory(r, memorySizer, memoryLimitPages)
   102  }
   103  
   104  func decodeGlobalSection(r *bytes.Reader, enabledFeatures api.CoreFeatures) ([]*wasm.Global, error) {
   105  	vs, _, err := leb128.DecodeUint32(r)
   106  	if err != nil {
   107  		return nil, fmt.Errorf("get size of vector: %w", err)
   108  	}
   109  
   110  	result := make([]*wasm.Global, vs)
   111  	for i := uint32(0); i < vs; i++ {
   112  		if result[i], err = decodeGlobal(r, enabledFeatures); err != nil {
   113  			return nil, fmt.Errorf("global[%d]: %w", i, err)
   114  		}
   115  	}
   116  	return result, nil
   117  }
   118  
   119  func decodeExportSection(r *bytes.Reader) ([]*wasm.Export, error) {
   120  	vs, _, sizeErr := leb128.DecodeUint32(r)
   121  	if sizeErr != nil {
   122  		return nil, fmt.Errorf("get size of vector: %v", sizeErr)
   123  	}
   124  
   125  	usedName := make(map[string]struct{}, vs)
   126  	exportSection := make([]*wasm.Export, 0, vs)
   127  	for i := wasm.Index(0); i < vs; i++ {
   128  		export, err := decodeExport(r)
   129  		if err != nil {
   130  			return nil, fmt.Errorf("read export: %w", err)
   131  		}
   132  		if _, ok := usedName[export.Name]; ok {
   133  			return nil, fmt.Errorf("export[%d] duplicates name %q", i, export.Name)
   134  		} else {
   135  			usedName[export.Name] = struct{}{}
   136  		}
   137  		exportSection = append(exportSection, export)
   138  	}
   139  	return exportSection, nil
   140  }
   141  
   142  func decodeStartSection(r *bytes.Reader) (*wasm.Index, error) {
   143  	vs, _, err := leb128.DecodeUint32(r)
   144  	if err != nil {
   145  		return nil, fmt.Errorf("get function index: %w", err)
   146  	}
   147  	return &vs, nil
   148  }
   149  
   150  func decodeElementSection(r *bytes.Reader, enabledFeatures api.CoreFeatures) ([]*wasm.ElementSegment, error) {
   151  	vs, _, err := leb128.DecodeUint32(r)
   152  	if err != nil {
   153  		return nil, fmt.Errorf("get size of vector: %w", err)
   154  	}
   155  
   156  	result := make([]*wasm.ElementSegment, vs)
   157  	for i := uint32(0); i < vs; i++ {
   158  		if result[i], err = decodeElementSegment(r, enabledFeatures); err != nil {
   159  			return nil, fmt.Errorf("read element: %w", err)
   160  		}
   161  	}
   162  	return result, nil
   163  }
   164  
   165  func decodeCodeSection(r *bytes.Reader) ([]*wasm.Code, error) {
   166  	vs, _, err := leb128.DecodeUint32(r)
   167  	if err != nil {
   168  		return nil, fmt.Errorf("get size of vector: %w", err)
   169  	}
   170  
   171  	result := make([]*wasm.Code, vs)
   172  	for i := uint32(0); i < vs; i++ {
   173  		if result[i], err = decodeCode(r); err != nil {
   174  			return nil, fmt.Errorf("read %d-th code segment: %v", i, err)
   175  		}
   176  	}
   177  	return result, nil
   178  }
   179  
   180  func decodeDataSection(r *bytes.Reader, enabledFeatures api.CoreFeatures) ([]*wasm.DataSegment, error) {
   181  	vs, _, err := leb128.DecodeUint32(r)
   182  	if err != nil {
   183  		return nil, fmt.Errorf("get size of vector: %w", err)
   184  	}
   185  
   186  	result := make([]*wasm.DataSegment, vs)
   187  	for i := uint32(0); i < vs; i++ {
   188  		if result[i], err = decodeDataSegment(r, enabledFeatures); err != nil {
   189  			return nil, fmt.Errorf("read data segment: %w", err)
   190  		}
   191  	}
   192  	return result, nil
   193  }
   194  
   195  func decodeDataCountSection(r *bytes.Reader) (count *uint32, err error) {
   196  	v, _, err := leb128.DecodeUint32(r)
   197  	if err != nil && err != io.EOF {
   198  		// data count is optional, so EOF is fine.
   199  		return nil, err
   200  	}
   201  	return &v, nil
   202  }
   203  
   204  // encodeSection encodes the sectionID, the size of its contents in bytes, followed by the contents.
   205  // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#sections%E2%91%A0
   206  func encodeSection(sectionID wasm.SectionID, contents []byte) []byte {
   207  	return append([]byte{sectionID}, encodeSizePrefixed(contents)...)
   208  }
   209  
   210  // encodeTypeSection encodes a wasm.SectionIDType for the given imports in WebAssembly 1.0 (20191205) Binary
   211  // Format.
   212  //
   213  // See encodeFunctionType
   214  // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#type-section%E2%91%A0
   215  func encodeTypeSection(types []*wasm.FunctionType) []byte {
   216  	contents := leb128.EncodeUint32(uint32(len(types)))
   217  	for _, t := range types {
   218  		contents = append(contents, encodeFunctionType(t)...)
   219  	}
   220  	return encodeSection(wasm.SectionIDType, contents)
   221  }
   222  
   223  // encodeImportSection encodes a wasm.SectionIDImport for the given imports in WebAssembly 1.0 (20191205) Binary
   224  // Format.
   225  //
   226  // See encodeImport
   227  // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#import-section%E2%91%A0
   228  func encodeImportSection(imports []*wasm.Import) []byte {
   229  	contents := leb128.EncodeUint32(uint32(len(imports)))
   230  	for _, i := range imports {
   231  		contents = append(contents, encodeImport(i)...)
   232  	}
   233  	return encodeSection(wasm.SectionIDImport, contents)
   234  }
   235  
   236  // encodeFunctionSection encodes a wasm.SectionIDFunction for the type indices associated with module-defined
   237  // functions in WebAssembly 1.0 (20191205) Binary Format.
   238  //
   239  // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#function-section%E2%91%A0
   240  func encodeFunctionSection(typeIndices []wasm.Index) []byte {
   241  	contents := leb128.EncodeUint32(uint32(len(typeIndices)))
   242  	for _, index := range typeIndices {
   243  		contents = append(contents, leb128.EncodeUint32(index)...)
   244  	}
   245  	return encodeSection(wasm.SectionIDFunction, contents)
   246  }
   247  
   248  // encodeCodeSection encodes a wasm.SectionIDCode for the module-defined function in WebAssembly 1.0 (20191205)
   249  // Binary Format.
   250  //
   251  // See encodeCode
   252  // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#code-section%E2%91%A0
   253  func encodeCodeSection(code []*wasm.Code) []byte {
   254  	contents := leb128.EncodeUint32(uint32(len(code)))
   255  	for _, i := range code {
   256  		contents = append(contents, encodeCode(i)...)
   257  	}
   258  	return encodeSection(wasm.SectionIDCode, contents)
   259  }
   260  
   261  // encodeTableSection encodes a wasm.SectionIDTable for the module-defined function in WebAssembly 1.0
   262  // (20191205) Binary Format.
   263  //
   264  // See encodeTable
   265  // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#table-section%E2%91%A0
   266  func encodeTableSection(tables []*wasm.Table) []byte {
   267  	var contents []byte = leb128.EncodeUint32(uint32(len(tables)))
   268  	for _, table := range tables {
   269  		contents = append(contents, encodeTable(table)...)
   270  	}
   271  	return encodeSection(wasm.SectionIDTable, contents)
   272  }
   273  
   274  // encodeMemorySection encodes a wasm.SectionIDMemory for the module-defined function in WebAssembly 1.0
   275  // (20191205) Binary Format.
   276  //
   277  // See encodeMemory
   278  // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#memory-section%E2%91%A0
   279  func encodeMemorySection(memory *wasm.Memory) []byte {
   280  	contents := append([]byte{1}, encodeMemory(memory)...)
   281  	return encodeSection(wasm.SectionIDMemory, contents)
   282  }
   283  
   284  // encodeGlobalSection encodes a wasm.SectionIDGlobal for the given globals in WebAssembly 1.0 (20191205) Binary
   285  // Format.
   286  //
   287  // See encodeGlobal
   288  // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#global-section%E2%91%A0
   289  func encodeGlobalSection(globals []*wasm.Global) []byte {
   290  	contents := leb128.EncodeUint32(uint32(len(globals)))
   291  	for _, g := range globals {
   292  		contents = append(contents, encodeGlobal(g)...)
   293  	}
   294  	return encodeSection(wasm.SectionIDGlobal, contents)
   295  }
   296  
   297  // encodeExportSection encodes a wasm.SectionIDExport for the given exports in WebAssembly 1.0 (20191205) Binary
   298  // Format.
   299  //
   300  // See encodeExport
   301  // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#export-section%E2%91%A0
   302  func encodeExportSection(exports []*wasm.Export) []byte {
   303  	contents := leb128.EncodeUint32(uint32(len(exports)))
   304  	for _, e := range exports {
   305  		contents = append(contents, encodeExport(e)...)
   306  	}
   307  	return encodeSection(wasm.SectionIDExport, contents)
   308  }
   309  
   310  // encodeStartSection encodes a wasm.SectionIDStart for the given function index in WebAssembly 1.0 (20191205)
   311  // Binary Format.
   312  //
   313  // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#start-section%E2%91%A0
   314  func encodeStartSection(funcidx wasm.Index) []byte {
   315  	return encodeSection(wasm.SectionIDStart, leb128.EncodeUint32(funcidx))
   316  }
   317  
   318  // encodeEelementSection encodes a wasm.SectionIDElement for the elements in WebAssembly 1.0 (20191205)
   319  // Binary Format.
   320  //
   321  // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#element-section%E2%91%A0
   322  func encodeElementSection(elements []*wasm.ElementSegment) []byte {
   323  	contents := leb128.EncodeUint32(uint32(len(elements)))
   324  	for _, e := range elements {
   325  		contents = append(contents, encodeElement(e)...)
   326  	}
   327  	return encodeSection(wasm.SectionIDElement, contents)
   328  }
   329  
   330  // encodeDataSection encodes a wasm.SectionIDData for the data in WebAssembly 1.0 (20191205)
   331  // Binary Format.
   332  //
   333  // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#data-section%E2%91%A0
   334  func encodeDataSection(datum []*wasm.DataSegment) []byte {
   335  	contents := leb128.EncodeUint32(uint32(len(datum)))
   336  	for _, d := range datum {
   337  		contents = append(contents, encodeDataSegment(d)...)
   338  	}
   339  	return encodeSection(wasm.SectionIDData, contents)
   340  }