const_expr.go

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