package binary
import (
"bytes"
"errors"
"fmt"
"github.com/tetratelabs/wazero/api"
"github.com/tetratelabs/wazero/internal/leb128"
"github.com/tetratelabs/wazero/internal/wasm"
)
func ensureElementKindFuncRef(r *bytes .Reader ) error {
elemKind , err := r .ReadByte ()
if err != nil {
return fmt .Errorf ("read element prefix: %w" , err )
}
if elemKind != 0x0 {
return fmt .Errorf ("element kind must be zero but was 0x%x" , elemKind )
}
return nil
}
func decodeElementInitValueVector(r *bytes .Reader ) ([]wasm .Index , error ) {
vs , _ , err := leb128 .DecodeUint32 (r )
if err != nil {
return nil , fmt .Errorf ("get size of vector: %w" , err )
}
vec := make ([]wasm .Index , vs )
for i := range vec {
u32 , _ , err := leb128 .DecodeUint32 (r )
if err != nil {
return nil , fmt .Errorf ("read function index: %w" , err )
}
if u32 >= wasm .MaximumFunctionIndex {
return nil , fmt .Errorf ("too large function index in Element init: %d" , u32 )
}
vec [i ] = u32
}
return vec , nil
}
func decodeElementConstExprVector(r *bytes .Reader , elemType wasm .RefType , enabledFeatures api .CoreFeatures ) ([]wasm .Index , error ) {
vs , _ , err := leb128 .DecodeUint32 (r )
if err != nil {
return nil , fmt .Errorf ("failed to get the size of constexpr vector: %w" , err )
}
vec := make ([]wasm .Index , vs )
for i := range vec {
var expr wasm .ConstantExpression
err := decodeConstantExpression (r , enabledFeatures , &expr )
if err != nil {
return nil , err
}
switch expr .Opcode {
case wasm .OpcodeRefFunc :
if elemType != wasm .RefTypeFuncref {
return nil , fmt .Errorf ("element type mismatch: want %s, but constexpr has funcref" , wasm .RefTypeName (elemType ))
}
v , _ , _ := leb128 .LoadUint32 (expr .Data )
if v >= wasm .MaximumFunctionIndex {
return nil , fmt .Errorf ("too large function index in Element init: %d" , v )
}
vec [i ] = v
case wasm .OpcodeRefNull :
if elemType != expr .Data [0 ] {
return nil , fmt .Errorf ("element type mismatch: want %s, but constexpr has %s" ,
wasm .RefTypeName (elemType ), wasm .RefTypeName (expr .Data [0 ]))
}
vec [i ] = wasm .ElementInitNullReference
case wasm .OpcodeGlobalGet :
i32 , _ , _ := leb128 .LoadInt32 (expr .Data )
vec [i ] = wasm .WrapGlobalIndexAsElementInit (wasm .Index (i32 ))
default :
return nil , fmt .Errorf ("const expr must be either ref.null or ref.func but was %s" , wasm .InstructionName (expr .Opcode ))
}
}
return vec , nil
}
func decodeElementRefType(r *bytes .Reader ) (ret wasm .RefType , err error ) {
ret , err = r .ReadByte ()
if err != nil {
err = fmt .Errorf ("read element ref type: %w" , err )
return
}
if ret != wasm .RefTypeFuncref && ret != wasm .RefTypeExternref {
return 0 , errors .New ("ref type must be funcref or externref for element as of WebAssembly 2.0" )
}
return
}
const (
elementSegmentPrefixLegacy = iota
elementSegmentPrefixPassiveFuncrefValueVector
elementSegmentPrefixActiveFuncrefValueVectorWithTableIndex
elementSegmentPrefixDeclarativeFuncrefValueVector
elementSegmentPrefixActiveFuncrefConstExprVector
elementSegmentPrefixPassiveConstExprVector
elementSegmentPrefixActiveConstExprVector
elementSegmentPrefixDeclarativeConstExprVector
)
func decodeElementSegment(r *bytes .Reader , enabledFeatures api .CoreFeatures , ret *wasm .ElementSegment ) error {
prefix , _ , err := leb128 .DecodeUint32 (r )
if err != nil {
return fmt .Errorf ("read element prefix: %w" , err )
}
if prefix != elementSegmentPrefixLegacy {
if err := enabledFeatures .RequireEnabled (api .CoreFeatureBulkMemoryOperations ); err != nil {
return fmt .Errorf ("non-zero prefix for element segment is invalid as %w" , err )
}
}
switch prefix {
case elementSegmentPrefixLegacy :
err = decodeConstantExpression (r , enabledFeatures , &ret .OffsetExpr )
if err != nil {
return fmt .Errorf ("read expr for offset: %w" , err )
}
ret .Init , err = decodeElementInitValueVector (r )
if err != nil {
return err
}
ret .Mode = wasm .ElementModeActive
ret .Type = wasm .RefTypeFuncref
return nil
case elementSegmentPrefixPassiveFuncrefValueVector :
if err = ensureElementKindFuncRef (r ); err != nil {
return err
}
ret .Init , err = decodeElementInitValueVector (r )
if err != nil {
return err
}
ret .Mode = wasm .ElementModePassive
ret .Type = wasm .RefTypeFuncref
return nil
case elementSegmentPrefixActiveFuncrefValueVectorWithTableIndex :
ret .TableIndex , _, err = leb128 .DecodeUint32 (r )
if err != nil {
return fmt .Errorf ("get size of vector: %w" , err )
}
if ret .TableIndex != 0 {
if err := enabledFeatures .RequireEnabled (api .CoreFeatureReferenceTypes ); err != nil {
return fmt .Errorf ("table index must be zero but was %d: %w" , ret .TableIndex , err )
}
}
err := decodeConstantExpression (r , enabledFeatures , &ret .OffsetExpr )
if err != nil {
return fmt .Errorf ("read expr for offset: %w" , err )
}
if err = ensureElementKindFuncRef (r ); err != nil {
return err
}
ret .Init , err = decodeElementInitValueVector (r )
if err != nil {
return err
}
ret .Mode = wasm .ElementModeActive
ret .Type = wasm .RefTypeFuncref
return nil
case elementSegmentPrefixDeclarativeFuncrefValueVector :
if err = ensureElementKindFuncRef (r ); err != nil {
return err
}
ret .Init , err = decodeElementInitValueVector (r )
if err != nil {
return err
}
ret .Type = wasm .RefTypeFuncref
ret .Mode = wasm .ElementModeDeclarative
return nil
case elementSegmentPrefixActiveFuncrefConstExprVector :
err := decodeConstantExpression (r , enabledFeatures , &ret .OffsetExpr )
if err != nil {
return fmt .Errorf ("read expr for offset: %w" , err )
}
ret .Init , err = decodeElementConstExprVector (r , wasm .RefTypeFuncref , enabledFeatures )
if err != nil {
return err
}
ret .Mode = wasm .ElementModeActive
ret .Type = wasm .RefTypeFuncref
return nil
case elementSegmentPrefixPassiveConstExprVector :
ret .Type , err = decodeElementRefType (r )
if err != nil {
return err
}
ret .Init , err = decodeElementConstExprVector (r , ret .Type , enabledFeatures )
if err != nil {
return err
}
ret .Mode = wasm .ElementModePassive
return nil
case elementSegmentPrefixActiveConstExprVector :
ret .TableIndex , _, err = leb128 .DecodeUint32 (r )
if err != nil {
return fmt .Errorf ("get size of vector: %w" , err )
}
if ret .TableIndex != 0 {
if err := enabledFeatures .RequireEnabled (api .CoreFeatureReferenceTypes ); err != nil {
return fmt .Errorf ("table index must be zero but was %d: %w" , ret .TableIndex , err )
}
}
err := decodeConstantExpression (r , enabledFeatures , &ret .OffsetExpr )
if err != nil {
return fmt .Errorf ("read expr for offset: %w" , err )
}
ret .Type , err = decodeElementRefType (r )
if err != nil {
return err
}
ret .Init , err = decodeElementConstExprVector (r , ret .Type , enabledFeatures )
if err != nil {
return err
}
ret .Mode = wasm .ElementModeActive
return nil
case elementSegmentPrefixDeclarativeConstExprVector :
ret .Type , err = decodeElementRefType (r )
if err != nil {
return err
}
ret .Init , err = decodeElementConstExprVector (r , ret .Type , enabledFeatures )
if err != nil {
return err
}
ret .Mode = wasm .ElementModeDeclarative
return nil
default :
return fmt .Errorf ("invalid element segment prefix: 0x%x" , prefix )
}
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .