wa-lang.org/wazero@v1.0.2/internal/wasm/binary/function.go (about) 1 package binary 2 3 import ( 4 "bytes" 5 "fmt" 6 7 "wa-lang.org/wazero/api" 8 "wa-lang.org/wazero/internal/leb128" 9 "wa-lang.org/wazero/internal/wasm" 10 ) 11 12 var nullary = []byte{0x60, 0, 0} 13 14 // encodedOneParam is a cache of wasm.FunctionType values for param length 1 and result length 0 15 var encodedOneParam = map[wasm.ValueType][]byte{ 16 wasm.ValueTypeI32: {0x60, 1, wasm.ValueTypeI32, 0}, 17 wasm.ValueTypeI64: {0x60, 1, wasm.ValueTypeI64, 0}, 18 wasm.ValueTypeF32: {0x60, 1, wasm.ValueTypeF32, 0}, 19 wasm.ValueTypeF64: {0x60, 1, wasm.ValueTypeF64, 0}, 20 } 21 22 // encodedOneResult is a cache of wasm.FunctionType values for param length 0 and result length 1 23 var encodedOneResult = map[wasm.ValueType][]byte{ 24 wasm.ValueTypeI32: {0x60, 0, 1, wasm.ValueTypeI32}, 25 wasm.ValueTypeI64: {0x60, 0, 1, wasm.ValueTypeI64}, 26 wasm.ValueTypeF32: {0x60, 0, 1, wasm.ValueTypeF32}, 27 wasm.ValueTypeF64: {0x60, 0, 1, wasm.ValueTypeF64}, 28 } 29 30 // encodeFunctionType returns the wasm.FunctionType encoded in WebAssembly 1.0 (20191205) Binary Format. 31 // 32 // Note: Function types are encoded by the byte 0x60 followed by the respective vectors of parameter and result types. 33 // See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#function-types%E2%91%A4 34 func encodeFunctionType(t *wasm.FunctionType) []byte { 35 paramCount, resultCount := len(t.Params), len(t.Results) 36 if paramCount == 0 && resultCount == 0 { 37 return nullary 38 } 39 if resultCount == 0 { 40 if paramCount == 1 { 41 if encoded, ok := encodedOneParam[t.Params[0]]; ok { 42 return encoded 43 } 44 } 45 return append(append([]byte{0x60}, encodeValTypes(t.Params)...), 0) 46 } else if resultCount == 1 { 47 if paramCount == 0 { 48 if encoded, ok := encodedOneResult[t.Results[0]]; ok { 49 return encoded 50 } 51 } 52 return append(append([]byte{0x60}, encodeValTypes(t.Params)...), 1, t.Results[0]) 53 } 54 // Only reached when "multi-value" is enabled because WebAssembly 1.0 (20191205) supports at most 1 result. 55 data := append([]byte{0x60}, encodeValTypes(t.Params)...) 56 return append(data, encodeValTypes(t.Results)...) 57 } 58 59 func decodeFunctionType(enabledFeatures api.CoreFeatures, r *bytes.Reader) (*wasm.FunctionType, error) { 60 b, err := r.ReadByte() 61 if err != nil { 62 return nil, fmt.Errorf("read leading byte: %w", err) 63 } 64 65 if b != 0x60 { 66 return nil, fmt.Errorf("%w: %#x != 0x60", ErrInvalidByte, b) 67 } 68 69 paramCount, _, err := leb128.DecodeUint32(r) 70 if err != nil { 71 return nil, fmt.Errorf("could not read parameter count: %w", err) 72 } 73 74 paramTypes, err := decodeValueTypes(r, paramCount) 75 if err != nil { 76 return nil, fmt.Errorf("could not read parameter types: %w", err) 77 } 78 79 resultCount, _, err := leb128.DecodeUint32(r) 80 if err != nil { 81 return nil, fmt.Errorf("could not read result count: %w", err) 82 } 83 84 // Guard >1.0 feature multi-value 85 if resultCount > 1 { 86 if err = enabledFeatures.RequireEnabled(api.CoreFeatureMultiValue); err != nil { 87 return nil, fmt.Errorf("multiple result types invalid as %v", err) 88 } 89 } 90 91 resultTypes, err := decodeValueTypes(r, resultCount) 92 if err != nil { 93 return nil, fmt.Errorf("could not read result types: %w", err) 94 } 95 96 ret := &wasm.FunctionType{ 97 Params: paramTypes, 98 Results: resultTypes, 99 } 100 return ret, nil 101 }