1 package binaryencoding
2
3 import (
4 "testing"
5
6 "github.com/tetratelabs/wazero/internal/leb128"
7 "github.com/tetratelabs/wazero/internal/testing/require"
8 "github.com/tetratelabs/wazero/internal/wasm"
9 )
10
11 func TestModule_Encode(t *testing.T) {
12 i32, f32 := wasm.ValueTypeI32, wasm.ValueTypeF32
13 zero := uint32(0)
14
15 tests := []struct {
16 name string
17 input *wasm.Module
18 expected []byte
19 }{
20 {
21 name: "empty",
22 input: &wasm.Module{},
23 expected: append(Magic, version...),
24 },
25 {
26 name: "only name section",
27 input: &wasm.Module{NameSection: &wasm.NameSection{ModuleName: "simple"}},
28 expected: append(append(Magic, version...),
29 wasm.SectionIDCustom, 0x0e,
30 0x04, 'n', 'a', 'm', 'e',
31 subsectionIDModuleName, 0x07,
32 0x06,
33 's', 'i', 'm', 'p', 'l', 'e'),
34 },
35 {
36 name: "type section",
37 input: &wasm.Module{
38 TypeSection: []wasm.FunctionType{
39 {},
40 {Params: []wasm.ValueType{i32, i32}, Results: []wasm.ValueType{i32}},
41 {Params: []wasm.ValueType{i32, i32, i32, i32}, Results: []wasm.ValueType{i32}},
42 },
43 },
44 expected: append(append(Magic, version...),
45 wasm.SectionIDType, 0x12,
46 0x03,
47 0x60, 0x00, 0x00,
48 0x60, 0x02, i32, i32, 0x01, i32,
49 0x60, 0x04, i32, i32, i32, i32, 0x01, i32,
50 ),
51 },
52 {
53 name: "type and import section",
54 input: &wasm.Module{
55 TypeSection: []wasm.FunctionType{
56 {Params: []wasm.ValueType{i32, i32}, Results: []wasm.ValueType{i32}},
57 {Params: []wasm.ValueType{f32, f32}, Results: []wasm.ValueType{f32}},
58 },
59 ImportSection: []wasm.Import{
60 {
61 Module: "Math", Name: "Mul",
62 Type: wasm.ExternTypeFunc,
63 DescFunc: 1,
64 }, {
65 Module: "Math", Name: "Add",
66 Type: wasm.ExternTypeFunc,
67 DescFunc: 0,
68 },
69 },
70 },
71 expected: append(append(Magic, version...),
72 wasm.SectionIDType, 0x0d,
73 0x02,
74 0x60, 0x02, i32, i32, 0x01, i32,
75 0x60, 0x02, f32, f32, 0x01, f32,
76 wasm.SectionIDImport, 0x17,
77 0x02,
78 0x04, 'M', 'a', 't', 'h', 0x03, 'M', 'u', 'l', wasm.ExternTypeFunc,
79 0x01,
80 0x04, 'M', 'a', 't', 'h', 0x03, 'A', 'd', 'd', wasm.ExternTypeFunc,
81 0x00,
82 ),
83 },
84 {
85 name: "type function and start section",
86 input: &wasm.Module{
87 TypeSection: []wasm.FunctionType{{}},
88 ImportSection: []wasm.Import{{
89 Module: "", Name: "hello",
90 Type: wasm.ExternTypeFunc,
91 DescFunc: 0,
92 }},
93 StartSection: &zero,
94 },
95 expected: append(append(Magic, version...),
96 wasm.SectionIDType, 0x04,
97 0x01,
98 0x60, 0x0, 0x0,
99 wasm.SectionIDImport, 0x0a,
100 0x01,
101 0x00, 0x05, 'h', 'e', 'l', 'l', 'o', wasm.ExternTypeFunc,
102 0x00,
103 wasm.SectionIDStart, 0x01,
104 0x00,
105 ),
106 },
107 {
108 name: "table and memory section",
109 input: &wasm.Module{
110 TableSection: []wasm.Table{{Min: 3, Type: wasm.RefTypeFuncref}},
111 MemorySection: &wasm.Memory{Min: 1, Max: 1, IsMaxEncoded: true},
112 },
113 expected: append(append(Magic, version...),
114 wasm.SectionIDTable, 0x04,
115 0x01,
116 wasm.RefTypeFuncref, 0x0, 0x03,
117 wasm.SectionIDMemory, 0x04,
118 0x01,
119 0x01, 0x01, 0x01,
120 ),
121 },
122 {
123 name: "exported func with instructions",
124 input: &wasm.Module{
125 TypeSection: []wasm.FunctionType{
126 {Params: []wasm.ValueType{i32, i32}, Results: []wasm.ValueType{i32}},
127 },
128 FunctionSection: []wasm.Index{0},
129 CodeSection: []wasm.Code{
130 {Body: []byte{wasm.OpcodeLocalGet, 0, wasm.OpcodeLocalGet, 1, wasm.OpcodeI32Add, wasm.OpcodeEnd}},
131 },
132 ExportSection: []wasm.Export{
133 {Name: "AddInt", Type: wasm.ExternTypeFunc, Index: wasm.Index(0)},
134 },
135 NameSection: &wasm.NameSection{
136 FunctionNames: wasm.NameMap{{Index: wasm.Index(0), Name: "addInt"}},
137 LocalNames: wasm.IndirectNameMap{
138 {Index: wasm.Index(0), NameMap: wasm.NameMap{
139 {Index: wasm.Index(0), Name: "value_1"},
140 {Index: wasm.Index(1), Name: "value_2"},
141 }},
142 },
143 },
144 },
145 expected: append(append(Magic, version...),
146 wasm.SectionIDType, 0x07,
147 0x01,
148 0x60, 0x02, i32, i32, 0x01, i32,
149 wasm.SectionIDFunction, 0x02,
150 0x01,
151 0x00,
152 wasm.SectionIDExport, 0x0a,
153 0x01,
154 0x06, 'A', 'd', 'd', 'I', 'n', 't',
155 wasm.ExternTypeFunc, 0x00,
156 wasm.SectionIDCode, 0x09,
157 0o1,
158 0o7,
159 0o0,
160 wasm.OpcodeLocalGet, 0,
161 wasm.OpcodeLocalGet, 1,
162 wasm.OpcodeI32Add,
163 wasm.OpcodeEnd,
164 wasm.SectionIDCustom, 0x27,
165 0x04, 'n', 'a', 'm', 'e',
166 subsectionIDFunctionNames, 0x09,
167 0x01,
168 0x00, 0x06, 'a', 'd', 'd', 'I', 'n', 't',
169 subsectionIDLocalNames, 0x15,
170 0x01,
171 0x00, 0x02,
172 0x00, 0x07, 'v', 'a', 'l', 'u', 'e', '_', '1',
173 0x01, 0x07, 'v', 'a', 'l', 'u', 'e', '_', '2',
174 ),
175 },
176 {
177 name: "exported global var",
178 input: &wasm.Module{
179 GlobalSection: []wasm.Global{
180 {
181 Type: wasm.GlobalType{ValType: i32, Mutable: true},
182 Init: wasm.ConstantExpression{Opcode: wasm.OpcodeI32Const, Data: leb128.EncodeInt32(0)},
183 },
184 },
185 ExportSection: []wasm.Export{
186 {Name: "sp", Type: wasm.ExternTypeGlobal, Index: wasm.Index(0)},
187 },
188 },
189 expected: append(append(Magic, version...),
190 wasm.SectionIDGlobal, 0x06,
191 0x01, wasm.ValueTypeI32, 0x01,
192 wasm.OpcodeI32Const, 0x00, wasm.OpcodeEnd,
193 wasm.SectionIDExport, 0x06,
194 0x01,
195 0x02, 's', 'p',
196 wasm.ExternTypeGlobal, 0x00,
197 ),
198 },
199 }
200
201 for _, tt := range tests {
202 tc := tt
203
204 t.Run(tc.name, func(t *testing.T) {
205 bytes := EncodeModule(tc.input)
206 require.Equal(t, tc.expected, bytes)
207 })
208 }
209 }
210
211 func TestModule_Encode_HostFunctionSection_Unsupported(t *testing.T) {
212
213 fn := func() {}
214
215 captured := require.CapturePanic(func() {
216 EncodeModule(&wasm.Module{
217 TypeSection: []wasm.FunctionType{{}},
218 CodeSection: []wasm.Code{wasm.MustParseGoReflectFuncCode(fn)},
219 })
220 })
221 require.EqualError(t, captured, "BUG: GoFunction is not encodable")
222 }
223
View as plain text