wa-lang.org/wazero@v1.0.2/internal/wasm/binary/data.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  // dataSegmentPrefix represents three types of data segments.
    14  //
    15  // https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/binary/modules.html#data-section
    16  type dataSegmentPrefix = uint32
    17  
    18  const (
    19  	// dataSegmentPrefixActive is the prefix for the version 1.0 compatible data segment, which is classified as "active" in 2.0.
    20  	dataSegmentPrefixActive dataSegmentPrefix = 0x0
    21  	// dataSegmentPrefixPassive prefixes the "passive" data segment as in version 2.0 specification.
    22  	dataSegmentPrefixPassive dataSegmentPrefix = 0x1
    23  	// dataSegmentPrefixActiveWithMemoryIndex is the active prefix with memory index encoded which is defined for futur use as of 2.0.
    24  	dataSegmentPrefixActiveWithMemoryIndex dataSegmentPrefix = 0x2
    25  )
    26  
    27  func decodeDataSegment(r *bytes.Reader, enabledFeatures api.CoreFeatures) (*wasm.DataSegment, error) {
    28  	dataSegmentPrefx, _, err := leb128.DecodeUint32(r)
    29  	if err != nil {
    30  		return nil, fmt.Errorf("read data segment prefix: %w", err)
    31  	}
    32  
    33  	if dataSegmentPrefx != dataSegmentPrefixActive {
    34  		if err := enabledFeatures.RequireEnabled(api.CoreFeatureBulkMemoryOperations); err != nil {
    35  			return nil, fmt.Errorf("non-zero prefix for data segment is invalid as %w", err)
    36  		}
    37  	}
    38  
    39  	var expr *wasm.ConstantExpression
    40  	switch dataSegmentPrefx {
    41  	case dataSegmentPrefixActive,
    42  		dataSegmentPrefixActiveWithMemoryIndex:
    43  		// Active data segment as in
    44  		// https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/binary/modules.html#data-section
    45  		if dataSegmentPrefx == 0x2 {
    46  			d, _, err := leb128.DecodeUint32(r)
    47  			if err != nil {
    48  				return nil, fmt.Errorf("read memory index: %v", err)
    49  			} else if d != 0 {
    50  				return nil, fmt.Errorf("memory index must be zero but was %d", d)
    51  			}
    52  		}
    53  
    54  		expr, err = decodeConstantExpression(r, enabledFeatures)
    55  		if err != nil {
    56  			return nil, fmt.Errorf("read offset expression: %v", err)
    57  		}
    58  	case dataSegmentPrefixPassive:
    59  		// Passive data segment doesn't need const expr nor memory index encoded.
    60  		// https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/binary/modules.html#data-section
    61  	default:
    62  		return nil, fmt.Errorf("invalid data segment prefix: 0x%x", dataSegmentPrefx)
    63  	}
    64  
    65  	vs, _, err := leb128.DecodeUint32(r)
    66  	if err != nil {
    67  		return nil, fmt.Errorf("get the size of vector: %v", err)
    68  	}
    69  
    70  	b := make([]byte, vs)
    71  	if _, err := io.ReadFull(r, b); err != nil {
    72  		return nil, fmt.Errorf("read bytes for init: %v", err)
    73  	}
    74  
    75  	return &wasm.DataSegment{
    76  		OffsetExpression: expr,
    77  		Init:             b,
    78  	}, nil
    79  }
    80  
    81  func encodeDataSegment(d *wasm.DataSegment) (ret []byte) {
    82  	// Currently multiple memories are not supported.
    83  	ret = append(ret, leb128.EncodeInt32(0)...)
    84  	ret = append(ret, encodeConstantExpression(d.OffsetExpression)...)
    85  	ret = append(ret, leb128.EncodeUint32(uint32(len(d.Init)))...)
    86  	ret = append(ret, d.Init...)
    87  	return
    88  }