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