github.com/taubyte/vm-wasm-utils@v1.0.2/binary/const_expr.go (about)

     1  package binary
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  
     7  	wasm "github.com/taubyte/vm-wasm-utils"
     8  	"github.com/taubyte/vm-wasm-utils/ieee754"
     9  	"github.com/taubyte/vm-wasm-utils/leb128"
    10  )
    11  
    12  func decodeConstantExpression(r *bytes.Reader, enabledFeatures wasm.Features) (*wasm.ConstantExpression, error) {
    13  	b, err := r.ReadByte()
    14  	if err != nil {
    15  		return nil, fmt.Errorf("read opcode: %v", err)
    16  	}
    17  
    18  	remainingBeforeData := int64(r.Len())
    19  	offsetAtData := r.Size() - remainingBeforeData
    20  
    21  	opcode := b
    22  	switch opcode {
    23  	case wasm.OpcodeI32Const:
    24  		// Treat constants as signed as their interpretation is not yet known per /RATIONALE.md
    25  		_, _, err = leb128.DecodeInt32(r)
    26  	case wasm.OpcodeI64Const:
    27  		// Treat constants as signed as their interpretation is not yet known per /RATIONALE.md
    28  		_, _, err = leb128.DecodeInt64(r)
    29  	case wasm.OpcodeF32Const:
    30  		_, err = ieee754.DecodeFloat32(r)
    31  	case wasm.OpcodeF64Const:
    32  		_, err = ieee754.DecodeFloat64(r)
    33  	case wasm.OpcodeGlobalGet:
    34  		_, _, err = leb128.DecodeUint32(r)
    35  	case wasm.OpcodeRefNull:
    36  		if err := enabledFeatures.Require(wasm.FeatureBulkMemoryOperations); err != nil {
    37  			return nil, fmt.Errorf("ref.null is not supported as %w", err)
    38  		}
    39  		reftype, err := r.ReadByte()
    40  		if err != nil {
    41  			return nil, fmt.Errorf("read reference type for ref.null: %w", err)
    42  		} else if reftype != wasm.RefTypeFuncref && reftype != wasm.RefTypeExternref {
    43  			return nil, fmt.Errorf("invalid type for ref.null: 0x%x", reftype)
    44  		}
    45  	case wasm.OpcodeRefFunc:
    46  		if err := enabledFeatures.Require(wasm.FeatureBulkMemoryOperations); err != nil {
    47  			return nil, fmt.Errorf("ref.func is not supported as %w", err)
    48  		}
    49  		// Parsing index.
    50  		_, _, err = leb128.DecodeUint32(r)
    51  	case wasm.OpcodeVecPrefix:
    52  		if err := enabledFeatures.Require(wasm.FeatureSIMD); err != nil {
    53  			return nil, fmt.Errorf("vector instructions are not supported as %w", err)
    54  		}
    55  		opcode, err = r.ReadByte()
    56  		if err != nil {
    57  			return nil, fmt.Errorf("read vector instruction opcode suffix: %w", err)
    58  		}
    59  
    60  		if opcode != wasm.OpcodeVecV128Const {
    61  			return nil, fmt.Errorf("invalid vector opcode for const expression: %#x", opcode)
    62  		}
    63  
    64  		remainingBeforeData = int64(r.Len())
    65  		offsetAtData = r.Size() - remainingBeforeData
    66  
    67  		n, err := r.Read(make([]byte, 16))
    68  		if err != nil {
    69  			return nil, fmt.Errorf("read vector const instruction immediates: %w", err)
    70  		} else if n != 16 {
    71  			return nil, fmt.Errorf("read vector const instruction immediates: needs 16 bytes but was %d bytes", n)
    72  		}
    73  	default:
    74  		return nil, fmt.Errorf("%v for const expression opt code: %#x", ErrInvalidByte, b)
    75  	}
    76  
    77  	if err != nil {
    78  		return nil, fmt.Errorf("read value: %v", err)
    79  	}
    80  
    81  	if b, err = r.ReadByte(); err != nil {
    82  		return nil, fmt.Errorf("look for end opcode: %v", err)
    83  	}
    84  
    85  	if b != wasm.OpcodeEnd {
    86  		return nil, fmt.Errorf("constant expression has been not terminated")
    87  	}
    88  
    89  	data := make([]byte, remainingBeforeData-int64(r.Len())-1)
    90  	if _, err := r.ReadAt(data, offsetAtData); err != nil {
    91  		return nil, fmt.Errorf("error re-buffering ConstantExpression.Data")
    92  	}
    93  
    94  	return &wasm.ConstantExpression{Opcode: opcode, Data: data}, nil
    95  }
    96  
    97  func encodeConstantExpression(expr *wasm.ConstantExpression) (ret []byte) {
    98  	ret = append(ret, expr.Opcode)
    99  	ret = append(ret, expr.Data...)
   100  	ret = append(ret, wasm.OpcodeEnd)
   101  	return
   102  }