1 // Copyright 2019 Wouter van Oortmerssen. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef WASM_BINARY_WRITER_TEST_H
16 #define WASM_BINARY_WRITER_TEST_H
17 
18 #include "wasm_binary_writer.h"
19 
20 using namespace std::string_view_literals;
21 
22 namespace WASM {
23 
24 // This is a simple test of the instruction encoding. The function returns a binary that
25 // when written to a file should pass e.g. wasm-validate.
SimpleBinaryWriterTest()26 std::vector<uint8_t> SimpleBinaryWriterTest() {
27     std::vector<uint8_t> vec;
28     BinaryWriter bw(vec);
29     // Write a (function) type section, to be referred to by functions below.
30     // For any of these sections, if you write them out of order, or don't match
31     // begin/end, you'll get an assert.
32     // As with everything, to refer to things in wasm, use a 0 based index.
33     bw.BeginSection(WASM::Section::Type);
34     // A list of arguments followed by a list of return values.
35     // You don't have to use the return value, but it may make referring to this
36     // type easier.
37     auto type_ii_i = bw.AddType({ WASM::I32, WASM::I32 }, { WASM::I32 });  // 0
38     auto type_i_v = bw.AddType({ WASM::I32 }, {});  // 1
39     bw.EndSection(WASM::Section::Type);
40 
41     // Import some functions, from the runtime compiled in other modules.
42     // For our example that will just be the printing function.
43     // Note: we assume this function has been declared with: extern "C"
44     // You can link against C++ functions as well if you don't mind dealing
45     // with name mangling.
46     bw.BeginSection(WASM::Section::Import);
47     auto import_print = bw.AddImportLinkFunction("print", type_i_v);  // 0
48     bw.EndSection(WASM::Section::Import);
49 
50     // Declare all the functions we will generate. Note this is just the type,
51     // the body of the code will follow below.
52     bw.BeginSection(WASM::Section::Function);
53     bw.AddFunction(type_ii_i);  // main()
54     bw.AddFunction(type_i_v);  // TestAllInstructions()
55     bw.EndSection(WASM::Section::Function);
56 
57     // We need this (and Element below) to be able to use call_indirect.
58     bw.BeginSection(WASM::Section::Table);
59     bw.AddTable();
60     bw.EndSection(WASM::Section::Table);
61 
62     // Declare the linear memory we want to use, with 1 initial page.
63     bw.BeginSection(WASM::Section::Memory);
64     bw.AddMemory(1);
65     bw.EndSection(WASM::Section::Memory);
66 
67     // Declare a global, used in the tests below.
68     bw.BeginSection(WASM::Section::Global);
69     bw.AddGlobal(WASM::I32, true);
70     bw.EmitI32Const(0);
71     bw.EmitEnd();
72     bw.EndSection(WASM::Section::Global);
73 
74     // Here we'd normally declare a "Start" section, but the linker will
75     // take care for that for us.
76 
77     // This initializes the Table declared above. Needed for call_indirect.
78     // For now we use a utility function that maps all functions ids 1:1 to the table.
79     bw.BeginSection(WASM::Section::Element);
80     bw.AddElementAllFunctions();
81     bw.EndSection(WASM::Section::Element);
82 
83     // Now the exciting part: emitting function bodies.
84     bw.BeginSection(WASM::Section::Code);
85 
86     // A list of 0 local types,
87     bw.AddCode({}, "main", false);
88     // Refers to data segment 0 at offset 0 below. This emits an i32.const
89     // instruction, whose immediate value will get relocated to refer to the
90     // data correctly.
91     bw.EmitI32ConstDataRef(0, 0);
92     bw.EmitCall(import_print);
93     bw.EmitI32Const(0);  // Return value.
94     bw.EmitEndFunction();
95 
96     // Test each instruction at least once. Needs to have correct stack inputs to pass
97     // wasm-validate etc, but is otherwise not meant to be meaningfull to execute.
98     bw.AddCode({}, "TestAllInstructions", false);
99     // Control flow.
100     bw.EmitNop();
101     bw.EmitBlock(WASM::VOID);
102         bw.EmitI32Const(true); bw.EmitBrIf(0);
103         bw.EmitBr(0);
104     bw.EmitEnd();
105     bw.EmitLoop(WASM::VOID);
106         bw.EmitI32Const(false); bw.EmitBrIf(0);
107     bw.EmitEnd();
108     bw.EmitI32Const(false); bw.EmitIf(WASM::I32);
109         bw.EmitI32Const(1);
110     bw.EmitElse();
111         bw.EmitI32Const(2);
112     bw.EmitEnd();
113     bw.EmitDrop();
114     bw.EmitBlock(WASM::VOID);
115         bw.EmitI32Const(2);
116         bw.EmitBrTable({}, 0);
117     bw.EmitEnd();
118     bw.EmitI32Const(0);
119     bw.EmitI32ConstFunctionRef(import_print);
120     bw.EmitCallIndirect(type_i_v);
121     bw.EmitI32Const(1); bw.EmitI32Const(2); bw.EmitI32Const(true); bw.EmitSelect();
122     // Variables.
123     bw.EmitGetLocal(0);
124     bw.EmitTeeLocal(0);
125     bw.EmitSetLocal(0);
126     bw.EmitGetGlobal(0);
127     bw.EmitSetGlobal(0);
128     // Memory.
129     for (int i = 0; i < 14; i++) bw.EmitI32Const(0);  // Address.
130     bw.EmitI32Load(0); bw.EmitDrop();
131     bw.EmitI64Load(0); bw.EmitDrop();
132     bw.EmitF32Load(0); bw.EmitDrop();
133     bw.EmitF64Load(0); bw.EmitDrop();
134     bw.EmitI32Load8S(0); bw.EmitDrop();
135     bw.EmitI32Load8U(0); bw.EmitDrop();
136     bw.EmitI32Load16S(0); bw.EmitDrop();
137     bw.EmitI32Load16U(0); bw.EmitDrop();
138     bw.EmitI64Load8S(0); bw.EmitDrop();
139     bw.EmitI64Load8U(0); bw.EmitDrop();
140     bw.EmitI64Load16S(0); bw.EmitDrop();
141     bw.EmitI64Load16U(0); bw.EmitDrop();
142     bw.EmitI64Load32S(0); bw.EmitDrop();
143     bw.EmitI64Load32U(0); bw.EmitDrop();
144     for (int i = 0; i < 11; i++) bw.EmitI32Const(0);  // Address.
145     bw.EmitI32Const(0); bw.EmitI32Store(0);
146     bw.EmitI64Const(0); bw.EmitI64Store(0);
147     bw.EmitF32Const(0); bw.EmitF32Store(0);
148     bw.EmitF64Const(0); bw.EmitF64Store(0);
149     bw.EmitI32Const(0); bw.EmitI32Store8(0);
150     bw.EmitI32Const(0); bw.EmitI32Store16(0);
151     bw.EmitI64Const(0); bw.EmitI64Store8(0);
152     bw.EmitI64Const(0); bw.EmitI64Store16(0);
153     bw.EmitI64Const(0); bw.EmitI64Store32(0);
154     bw.EmitCurrentMemory();
155     bw.EmitDrop();
156     bw.EmitGrowMemory();
157     // Equality operators.
158     bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32Eqz(); bw.EmitDrop();
159     bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32Eq(); bw.EmitDrop();
160     bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32Ne(); bw.EmitDrop();
161     bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32LtS(); bw.EmitDrop();
162     bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32LtU(); bw.EmitDrop();
163     bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32GtS(); bw.EmitDrop();
164     bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32GtU(); bw.EmitDrop();
165     bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32LeS(); bw.EmitDrop();
166     bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32LeU(); bw.EmitDrop();
167     bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32GeS(); bw.EmitDrop();
168     bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32GeU(); bw.EmitDrop();
169     bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64Eqz(); bw.EmitDrop();
170     bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64Eq(); bw.EmitDrop();
171     bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64Ne(); bw.EmitDrop();
172     bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64LtS(); bw.EmitDrop();
173     bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64LtU(); bw.EmitDrop();
174     bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64GtS(); bw.EmitDrop();
175     bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64GtU(); bw.EmitDrop();
176     bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64LeS(); bw.EmitDrop();
177     bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64LeU(); bw.EmitDrop();
178     bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64GeS(); bw.EmitDrop();
179     bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64GeU(); bw.EmitDrop();
180     bw.EmitF32Const(0); bw.EmitF32Const(0); bw.EmitF32Eq(); bw.EmitDrop();
181     bw.EmitF32Const(0); bw.EmitF32Const(0); bw.EmitF32Ne(); bw.EmitDrop();
182     bw.EmitF32Const(0); bw.EmitF32Const(0); bw.EmitF32Lt(); bw.EmitDrop();
183     bw.EmitF32Const(0); bw.EmitF32Const(0); bw.EmitF32Gt(); bw.EmitDrop();
184     bw.EmitF32Const(0); bw.EmitF32Const(0); bw.EmitF32Le(); bw.EmitDrop();
185     bw.EmitF32Const(0); bw.EmitF32Const(0); bw.EmitF32Ge(); bw.EmitDrop();
186     bw.EmitF64Const(0); bw.EmitF64Const(0); bw.EmitF64Eq(); bw.EmitDrop();
187     bw.EmitF64Const(0); bw.EmitF64Const(0); bw.EmitF64Ne(); bw.EmitDrop();
188     bw.EmitF64Const(0); bw.EmitF64Const(0); bw.EmitF64Lt(); bw.EmitDrop();
189     bw.EmitF64Const(0); bw.EmitF64Const(0); bw.EmitF64Gt(); bw.EmitDrop();
190     bw.EmitF64Const(0); bw.EmitF64Const(0); bw.EmitF64Le(); bw.EmitDrop();
191     bw.EmitF64Const(0); bw.EmitF64Const(0); bw.EmitF64Ge(); bw.EmitDrop();
192     // Numeric operators.
193     bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32Clz(); bw.EmitDrop();
194     bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32Ctz(); bw.EmitDrop();
195     bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32PopCnt(); bw.EmitDrop();
196     bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32Add(); bw.EmitDrop();
197     bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32Sub(); bw.EmitDrop();
198     bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32Mul(); bw.EmitDrop();
199     bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32DivS(); bw.EmitDrop();
200     bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32DivU(); bw.EmitDrop();
201     bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32RemS(); bw.EmitDrop();
202     bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32RemU(); bw.EmitDrop();
203     bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32And(); bw.EmitDrop();
204     bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32Or(); bw.EmitDrop();
205     bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32Xor(); bw.EmitDrop();
206     bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32Shl(); bw.EmitDrop();
207     bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32ShrS(); bw.EmitDrop();
208     bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32ShrU(); bw.EmitDrop();
209     bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32RotL(); bw.EmitDrop();
210     bw.EmitI32Const(0); bw.EmitI32Const(0); bw.EmitI32RotR(); bw.EmitDrop();
211     bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64Clz(); bw.EmitDrop();
212     bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64Ctz(); bw.EmitDrop();
213     bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64PopCnt(); bw.EmitDrop();
214     bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64Add(); bw.EmitDrop();
215     bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64Sub(); bw.EmitDrop();
216     bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64Mul(); bw.EmitDrop();
217     bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64DivS(); bw.EmitDrop();
218     bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64DivU(); bw.EmitDrop();
219     bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64RemS(); bw.EmitDrop();
220     bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64RemU(); bw.EmitDrop();
221     bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64And(); bw.EmitDrop();
222     bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64Or(); bw.EmitDrop();
223     bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64Xor(); bw.EmitDrop();
224     bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64Shl(); bw.EmitDrop();
225     bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64ShrS(); bw.EmitDrop();
226     bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64ShrU(); bw.EmitDrop();
227     bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64RotL(); bw.EmitDrop();
228     bw.EmitI64Const(0); bw.EmitI64Const(0); bw.EmitI64RotR(); bw.EmitDrop();
229     bw.EmitF32Const(0); bw.EmitF32Const(0); bw.EmitF32Abs(); bw.EmitDrop();
230     bw.EmitF32Const(0); bw.EmitF32Const(0); bw.EmitF32Neg(); bw.EmitDrop();
231     bw.EmitF32Const(0); bw.EmitF32Const(0); bw.EmitF32Ceil(); bw.EmitDrop();
232     bw.EmitF32Const(0); bw.EmitF32Const(0); bw.EmitF32Floor(); bw.EmitDrop();
233     bw.EmitF32Const(0); bw.EmitF32Const(0); bw.EmitF32Trunc(); bw.EmitDrop();
234     bw.EmitF32Const(0); bw.EmitF32Const(0); bw.EmitF32Nearest(); bw.EmitDrop();
235     bw.EmitF32Const(0); bw.EmitF32Const(0); bw.EmitF32Sqrt(); bw.EmitDrop();
236     bw.EmitF32Const(0); bw.EmitF32Const(0); bw.EmitF32Add(); bw.EmitDrop();
237     bw.EmitF32Const(0); bw.EmitF32Const(0); bw.EmitF32Sub(); bw.EmitDrop();
238     bw.EmitF32Const(0); bw.EmitF32Const(0); bw.EmitF32Mul(); bw.EmitDrop();
239     bw.EmitF32Const(0); bw.EmitF32Const(0); bw.EmitF32Div(); bw.EmitDrop();
240     bw.EmitF32Const(0); bw.EmitF32Const(0); bw.EmitF32Min(); bw.EmitDrop();
241     bw.EmitF32Const(0); bw.EmitF32Const(0); bw.EmitF32Max(); bw.EmitDrop();
242     bw.EmitF32Const(0); bw.EmitF32Const(0); bw.EmitF32CopySign(); bw.EmitDrop();
243     bw.EmitF64Const(0); bw.EmitF64Const(0); bw.EmitF64Abs(); bw.EmitDrop();
244     bw.EmitF64Const(0); bw.EmitF64Const(0); bw.EmitF64Neg(); bw.EmitDrop();
245     bw.EmitF64Const(0); bw.EmitF64Const(0); bw.EmitF64Ceil(); bw.EmitDrop();
246     bw.EmitF64Const(0); bw.EmitF64Const(0); bw.EmitF64Floor(); bw.EmitDrop();
247     bw.EmitF64Const(0); bw.EmitF64Const(0); bw.EmitF64Trunc(); bw.EmitDrop();
248     bw.EmitF64Const(0); bw.EmitF64Const(0); bw.EmitF64Nearest(); bw.EmitDrop();
249     bw.EmitF64Const(0); bw.EmitF64Const(0); bw.EmitF64Sqrt(); bw.EmitDrop();
250     bw.EmitF64Const(0); bw.EmitF64Const(0); bw.EmitF64Add(); bw.EmitDrop();
251     bw.EmitF64Const(0); bw.EmitF64Const(0); bw.EmitF64Sub(); bw.EmitDrop();
252     bw.EmitF64Const(0); bw.EmitF64Const(0); bw.EmitF64Mul(); bw.EmitDrop();
253     bw.EmitF64Const(0); bw.EmitF64Const(0); bw.EmitF64Div(); bw.EmitDrop();
254     bw.EmitF64Const(0); bw.EmitF64Const(0); bw.EmitF64Min(); bw.EmitDrop();
255     bw.EmitF64Const(0); bw.EmitF64Const(0); bw.EmitF64Max(); bw.EmitDrop();
256     bw.EmitF64Const(0); bw.EmitF64Const(0); bw.EmitF64CopySign(); bw.EmitDrop();
257     // Coversion operations.
258     bw.EmitI64Const(0); bw.EmitI32WrapI64(); bw.EmitDrop();
259     bw.EmitF32Const(0); bw.EmitI32TruncSF32(); bw.EmitDrop();
260     bw.EmitF32Const(0); bw.EmitI32TruncUF32(); bw.EmitDrop();
261     bw.EmitF64Const(0); bw.EmitI32TruncSF64(); bw.EmitDrop();
262     bw.EmitF64Const(0); bw.EmitI32TruncUF64(); bw.EmitDrop();
263     bw.EmitI32Const(0); bw.EmitI64ExtendSI32(); bw.EmitDrop();
264     bw.EmitI32Const(0); bw.EmitI64ExtendUI32(); bw.EmitDrop();
265     bw.EmitF32Const(0); bw.EmitI64TruncSF32(); bw.EmitDrop();
266     bw.EmitF32Const(0); bw.EmitI64TruncUF32(); bw.EmitDrop();
267     bw.EmitF64Const(0); bw.EmitI64TruncSF64(); bw.EmitDrop();
268     bw.EmitF64Const(0); bw.EmitI64TruncUF64(); bw.EmitDrop();
269     bw.EmitI32Const(0); bw.EmitF32ConvertSI32(); bw.EmitDrop();
270     bw.EmitI32Const(0); bw.EmitF32ConvertUI32(); bw.EmitDrop();
271     bw.EmitI64Const(0); bw.EmitF32ConvertSI64(); bw.EmitDrop();
272     bw.EmitI64Const(0); bw.EmitF32ConvertUI64(); bw.EmitDrop();
273     bw.EmitF64Const(0); bw.EmitF32DemoteF64(); bw.EmitDrop();
274     bw.EmitI32Const(0); bw.EmitF64ConvertSI32(); bw.EmitDrop();
275     bw.EmitI32Const(0); bw.EmitF64ConvertUI32(); bw.EmitDrop();
276     bw.EmitI64Const(0); bw.EmitF64ConvertSI64(); bw.EmitDrop();
277     bw.EmitI64Const(0); bw.EmitF64ConvertUI64(); bw.EmitDrop();
278     bw.EmitF32Const(0); bw.EmitF64PromoteF32(); bw.EmitDrop();
279     // Reinterpretations.
280     bw.EmitF32Const(0); bw.EmitI32ReinterpretF32(); bw.EmitDrop();
281     bw.EmitF64Const(0); bw.EmitI64ReinterpretF64(); bw.EmitDrop();
282     bw.EmitI32Const(0); bw.EmitF32ReinterpretI32(); bw.EmitDrop();
283     bw.EmitI64Const(0); bw.EmitF64ReinterpretI64(); bw.EmitDrop();
284     // More control flow.
285     bw.EmitReturn();
286     bw.EmitUnreachable();
287     bw.EmitEndFunction();
288 
289     bw.EndSection(WASM::Section::Code);
290 
291     // Add all our static data.
292     bw.BeginSection(WASM::Section::Data);
293 
294     // This is our first segment, we referred to this above as 0.
295     auto hello = "Hello, World\n\0"sv;
296     // Data, name, and alignment.
297     bw.AddData(hello, "hello", 0);
298 
299     // Create another segment, this time with function references.
300     int function_ref = (int)bw.GetNumFunctionImports() + 0;  // Refers to main()
301     bw.AddData(std::string_view((char *)&function_ref, sizeof(int)), "funids", sizeof(int));
302     bw.DataFunctionRef(function_ref, 0);  // Reloc it.
303 
304     bw.EndSection(WASM::Section::Data);
305 
306     // This call does all the remaining work of generating the linking
307     // information, and wrapping up the file.
308     bw.Finish();
309     return vec;
310 }
311 
312 }  // namespace WASM
313 
314 #endif  // WASM_BINARY_WRITER_TEST_H
315