@aptre/v86 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/LICENSE +22 -0
  2. package/LICENSE.MIT +22 -0
  3. package/Readme.md +237 -0
  4. package/dist/v86.browser.js +26666 -0
  5. package/dist/v86.browser.js.map +7 -0
  6. package/dist/v86.js +26632 -0
  7. package/dist/v86.js.map +7 -0
  8. package/gen/generate_analyzer.ts +512 -0
  9. package/gen/generate_interpreter.ts +522 -0
  10. package/gen/generate_jit.ts +624 -0
  11. package/gen/rust_ast.ts +107 -0
  12. package/gen/util.ts +35 -0
  13. package/gen/x86_table.ts +1836 -0
  14. package/lib/9p.ts +1547 -0
  15. package/lib/filesystem.ts +1879 -0
  16. package/lib/marshall.ts +168 -0
  17. package/lib/softfloat/softfloat.c +32501 -0
  18. package/lib/zstd/zstddeclib.c +13520 -0
  19. package/package.json +75 -0
  20. package/src/acpi.ts +267 -0
  21. package/src/browser/dummy_screen.ts +106 -0
  22. package/src/browser/fake_network.ts +1771 -0
  23. package/src/browser/fetch_network.ts +361 -0
  24. package/src/browser/filestorage.ts +124 -0
  25. package/src/browser/inbrowser_network.ts +57 -0
  26. package/src/browser/keyboard.ts +564 -0
  27. package/src/browser/main.ts +3415 -0
  28. package/src/browser/mouse.ts +255 -0
  29. package/src/browser/network.ts +142 -0
  30. package/src/browser/print_stats.ts +336 -0
  31. package/src/browser/screen.ts +978 -0
  32. package/src/browser/serial.ts +316 -0
  33. package/src/browser/speaker.ts +1223 -0
  34. package/src/browser/starter.ts +1688 -0
  35. package/src/browser/wisp_network.ts +332 -0
  36. package/src/browser/worker_bus.ts +64 -0
  37. package/src/buffer.ts +652 -0
  38. package/src/bus.ts +78 -0
  39. package/src/const.ts +128 -0
  40. package/src/cpu.ts +2891 -0
  41. package/src/dma.ts +474 -0
  42. package/src/elf.ts +251 -0
  43. package/src/floppy.ts +1778 -0
  44. package/src/ide.ts +3455 -0
  45. package/src/io.ts +504 -0
  46. package/src/iso9660.ts +317 -0
  47. package/src/kernel.ts +250 -0
  48. package/src/lib.ts +645 -0
  49. package/src/log.ts +149 -0
  50. package/src/main.ts +199 -0
  51. package/src/ne2k.ts +1589 -0
  52. package/src/pci.ts +815 -0
  53. package/src/pit.ts +406 -0
  54. package/src/ps2.ts +820 -0
  55. package/src/rtc.ts +537 -0
  56. package/src/rust/analysis.rs +101 -0
  57. package/src/rust/codegen.rs +2660 -0
  58. package/src/rust/config.rs +3 -0
  59. package/src/rust/control_flow.rs +425 -0
  60. package/src/rust/cpu/apic.rs +658 -0
  61. package/src/rust/cpu/arith.rs +1207 -0
  62. package/src/rust/cpu/call_indirect.rs +2 -0
  63. package/src/rust/cpu/cpu.rs +4501 -0
  64. package/src/rust/cpu/fpu.rs +923 -0
  65. package/src/rust/cpu/global_pointers.rs +112 -0
  66. package/src/rust/cpu/instructions.rs +2486 -0
  67. package/src/rust/cpu/instructions_0f.rs +5261 -0
  68. package/src/rust/cpu/ioapic.rs +316 -0
  69. package/src/rust/cpu/memory.rs +351 -0
  70. package/src/rust/cpu/misc_instr.rs +613 -0
  71. package/src/rust/cpu/mod.rs +16 -0
  72. package/src/rust/cpu/modrm.rs +133 -0
  73. package/src/rust/cpu/pic.rs +402 -0
  74. package/src/rust/cpu/sse_instr.rs +361 -0
  75. package/src/rust/cpu/string.rs +701 -0
  76. package/src/rust/cpu/vga.rs +175 -0
  77. package/src/rust/cpu_context.rs +69 -0
  78. package/src/rust/dbg.rs +98 -0
  79. package/src/rust/gen/analyzer.rs +3807 -0
  80. package/src/rust/gen/analyzer0f.rs +3992 -0
  81. package/src/rust/gen/interpreter.rs +4447 -0
  82. package/src/rust/gen/interpreter0f.rs +5404 -0
  83. package/src/rust/gen/jit.rs +5080 -0
  84. package/src/rust/gen/jit0f.rs +5547 -0
  85. package/src/rust/gen/mod.rs +14 -0
  86. package/src/rust/jit.rs +2443 -0
  87. package/src/rust/jit_instructions.rs +7881 -0
  88. package/src/rust/js_api.rs +6 -0
  89. package/src/rust/leb.rs +46 -0
  90. package/src/rust/lib.rs +29 -0
  91. package/src/rust/modrm.rs +330 -0
  92. package/src/rust/opstats.rs +249 -0
  93. package/src/rust/page.rs +15 -0
  94. package/src/rust/paging.rs +25 -0
  95. package/src/rust/prefix.rs +15 -0
  96. package/src/rust/profiler.rs +155 -0
  97. package/src/rust/regs.rs +38 -0
  98. package/src/rust/softfloat.rs +286 -0
  99. package/src/rust/state_flags.rs +27 -0
  100. package/src/rust/wasmgen/mod.rs +2 -0
  101. package/src/rust/wasmgen/wasm_builder.rs +1047 -0
  102. package/src/rust/wasmgen/wasm_opcodes.rs +221 -0
  103. package/src/rust/zstd.rs +105 -0
  104. package/src/sb16.ts +1928 -0
  105. package/src/state.ts +359 -0
  106. package/src/uart.ts +472 -0
  107. package/src/vga.ts +2791 -0
  108. package/src/virtio.ts +1756 -0
  109. package/src/virtio_balloon.ts +273 -0
  110. package/src/virtio_console.ts +372 -0
  111. package/src/virtio_net.ts +326 -0
@@ -0,0 +1,1047 @@
1
+ use std::collections::HashMap;
2
+ use std::mem::transmute;
3
+
4
+ use crate::leb::{
5
+ write_fixed_leb16_at_idx, write_fixed_leb32_at_idx, write_leb_i32, write_leb_i64, write_leb_u32,
6
+ };
7
+ use crate::wasmgen::wasm_opcodes as op;
8
+
9
+ pub trait SafeToU8 {
10
+ fn safe_to_u8(self) -> u8;
11
+ }
12
+ impl SafeToU8 for usize {
13
+ fn safe_to_u8(self) -> u8 {
14
+ dbg_assert!(self <= ::std::u8::MAX as usize);
15
+ self as u8
16
+ }
17
+ }
18
+
19
+ pub trait SafeToU16 {
20
+ fn safe_to_u16(self) -> u16;
21
+ }
22
+ impl SafeToU16 for usize {
23
+ fn safe_to_u16(self) -> u16 {
24
+ dbg_assert!(self <= ::std::u16::MAX as usize);
25
+ self as u16
26
+ }
27
+ }
28
+
29
+ #[derive(PartialEq)]
30
+ #[allow(non_camel_case_types)]
31
+ enum FunctionType {
32
+ FN0,
33
+ FN1,
34
+ FN2,
35
+ FN3,
36
+
37
+ FN0_RET,
38
+ FN0_RET_I64,
39
+ FN1_RET,
40
+ FN2_RET,
41
+
42
+ FN1_RET_I64,
43
+ FN1_F32_RET,
44
+ FN1_F64_RET,
45
+
46
+ FN2_I32_I64,
47
+ FN2_I64_I32,
48
+ FN2_I64_I32_RET,
49
+ FN2_I64_I32_RET_I64,
50
+ FN2_F32_I32,
51
+
52
+ FN3_RET,
53
+
54
+ FN3_I64_I32_I32,
55
+ FN3_I32_I64_I32,
56
+ FN3_I32_I64_I32_RET,
57
+ FN4_I32_I64_I64_I32_RET,
58
+ // When adding at the end, update LAST below
59
+ }
60
+
61
+ impl FunctionType {
62
+ pub fn of_u8(x: u8) -> FunctionType {
63
+ dbg_assert!(x <= FunctionType::LAST as u8);
64
+ unsafe { transmute(x) }
65
+ }
66
+ pub fn to_u8(self: FunctionType) -> u8 { self as u8 }
67
+ pub const LAST: FunctionType = FunctionType::FN4_I32_I64_I64_I32_RET;
68
+ }
69
+
70
+ pub const WASM_MODULE_ARGUMENT_COUNT: u8 = 1;
71
+
72
+ pub struct WasmBuilder {
73
+ output: Vec<u8>,
74
+ instruction_body: Vec<u8>,
75
+
76
+ idx_import_table_size: usize, // for rewriting once finished
77
+ idx_import_count: usize, // for rewriting once finished
78
+ idx_import_entries: usize, // for searching the imports
79
+
80
+ import_table_size: usize, // the current import table size (to avoid reading 2 byte leb)
81
+ import_count: u16, // same as above
82
+
83
+ initial_static_size: usize, // size of module after initialization, rest is drained on reset
84
+
85
+ // label for referencing block/if/loop constructs directly via branch instructions
86
+ next_label: Label,
87
+ label_stack: Vec<Label>,
88
+ label_to_depth: HashMap<Label, usize>,
89
+
90
+ free_locals_i32: Vec<WasmLocal>,
91
+ free_locals_i64: Vec<WasmLocalI64>,
92
+ local_count: u8,
93
+ pub arg_local_initial_state: WasmLocal,
94
+ }
95
+
96
+ #[derive(Eq, PartialEq)]
97
+ pub struct WasmLocal(u8);
98
+ impl WasmLocal {
99
+ pub fn idx(&self) -> u8 { self.0 }
100
+ /// Unsafe: Can result in multiple free's. Should only be used for locals that are used during
101
+ /// the whole module (for example, registers)
102
+ pub fn unsafe_clone(&self) -> WasmLocal { WasmLocal(self.0) }
103
+ }
104
+
105
+ pub struct WasmLocalI64(u8);
106
+ impl WasmLocalI64 {
107
+ pub fn idx(&self) -> u8 { self.0 }
108
+ }
109
+
110
+ #[derive(Copy, Clone, Eq, Hash, PartialEq)]
111
+ pub struct Label(u32);
112
+ impl Label {
113
+ const ZERO: Label = Label(0);
114
+ fn next(&self) -> Label { Label(self.0.wrapping_add(1)) }
115
+ }
116
+
117
+ impl WasmBuilder {
118
+ pub fn new() -> Self {
119
+ let mut b = WasmBuilder {
120
+ output: Vec::with_capacity(256),
121
+ instruction_body: Vec::with_capacity(256),
122
+
123
+ idx_import_table_size: 0,
124
+ idx_import_count: 0,
125
+ idx_import_entries: 0,
126
+
127
+ import_table_size: 2,
128
+ import_count: 0,
129
+
130
+ initial_static_size: 0,
131
+
132
+ label_to_depth: HashMap::new(),
133
+ label_stack: Vec::new(),
134
+ next_label: Label::ZERO,
135
+
136
+ free_locals_i32: Vec::with_capacity(8),
137
+ free_locals_i64: Vec::with_capacity(8),
138
+ local_count: 0,
139
+ arg_local_initial_state: WasmLocal(0),
140
+ };
141
+ b.init();
142
+ b
143
+ }
144
+
145
+ fn init(&mut self) {
146
+ self.output.extend("\0asm".as_bytes());
147
+
148
+ // wasm version in leb128, 4 bytes
149
+ self.output.push(op::WASM_VERSION);
150
+ self.output.push(0);
151
+ self.output.push(0);
152
+ self.output.push(0);
153
+
154
+ self.write_type_section();
155
+ self.write_import_section_preamble();
156
+
157
+ // store state of current pointers etc. so we can reset them later
158
+ self.initial_static_size = self.output.len();
159
+ }
160
+
161
+ pub fn reset(&mut self) {
162
+ self.output.drain(self.initial_static_size..);
163
+ self.set_import_table_size(2);
164
+ self.set_import_count(0);
165
+ self.instruction_body.clear();
166
+ self.free_locals_i32.clear();
167
+ self.free_locals_i64.clear();
168
+ self.local_count = 0;
169
+
170
+ dbg_assert!(self.label_to_depth.is_empty());
171
+ dbg_assert!(self.label_stack.is_empty());
172
+ self.next_label = Label::ZERO;
173
+ }
174
+
175
+ pub fn finish(&mut self) -> usize {
176
+ dbg_assert!(self.label_to_depth.is_empty());
177
+ dbg_assert!(self.label_stack.is_empty());
178
+
179
+ self.write_memory_import();
180
+ self.write_function_section();
181
+ self.write_export_section();
182
+
183
+ // write code section preamble
184
+ self.output.push(op::SC_CODE);
185
+
186
+ let idx_code_section_size = self.output.len(); // we will write to this location later
187
+ self.output.push(0);
188
+ self.output.push(0); // write temp val for now using 4 bytes
189
+ self.output.push(0);
190
+ self.output.push(0);
191
+
192
+ self.output.push(1); // number of function bodies: just 1
193
+
194
+ // same as above but for body size of the function
195
+ let idx_fn_body_size = self.output.len();
196
+ self.output.push(0);
197
+ self.output.push(0);
198
+ self.output.push(0);
199
+ self.output.push(0);
200
+
201
+ dbg_assert!(
202
+ self.local_count as usize == self.free_locals_i32.len() + self.free_locals_i64.len(),
203
+ "All locals should have been freed"
204
+ );
205
+
206
+ let free_locals_i32 = &self.free_locals_i32;
207
+ let free_locals_i64 = &self.free_locals_i64;
208
+
209
+ let locals = (0..self.local_count).map(|i| {
210
+ let local_index = WASM_MODULE_ARGUMENT_COUNT + i;
211
+ if free_locals_i64.iter().any(|v| v.idx() == local_index) {
212
+ op::TYPE_I64
213
+ }
214
+ else {
215
+ dbg_assert!(free_locals_i32.iter().any(|v| v.idx() == local_index));
216
+ op::TYPE_I32
217
+ }
218
+ });
219
+ let mut groups = vec![];
220
+ for local_type in locals {
221
+ if let Some(last) = groups.last_mut() {
222
+ let (last_type, last_count) = *last;
223
+ if last_type == local_type {
224
+ *last = (local_type, last_count + 1);
225
+ continue;
226
+ }
227
+ }
228
+ groups.push((local_type, 1));
229
+ }
230
+ dbg_assert!(groups.len() < 128);
231
+ self.output.push(groups.len().safe_to_u8());
232
+ for (local_type, count) in groups {
233
+ dbg_assert!(count < 128);
234
+ self.output.push(count);
235
+ self.output.push(local_type);
236
+ }
237
+
238
+ self.output.append(&mut self.instruction_body);
239
+
240
+ self.output.push(op::OP_END);
241
+
242
+ // write the actual sizes to the pointer locations stored above. We subtract 4 from the actual
243
+ // value because the ptr itself points to four bytes
244
+ let fn_body_size = (self.output.len() - idx_fn_body_size - 4) as u32;
245
+ write_fixed_leb32_at_idx(&mut self.output, idx_fn_body_size, fn_body_size);
246
+
247
+ let code_section_size = (self.output.len() - idx_code_section_size - 4) as u32;
248
+ write_fixed_leb32_at_idx(&mut self.output, idx_code_section_size, code_section_size);
249
+
250
+ self.output.len()
251
+ }
252
+
253
+ pub fn write_type_section(&mut self) {
254
+ self.output.push(op::SC_TYPE);
255
+
256
+ let idx_section_size = self.output.len();
257
+ self.output.push(0);
258
+ self.output.push(0);
259
+
260
+ let nr_of_function_types = FunctionType::to_u8(FunctionType::LAST) + 1;
261
+ dbg_assert!(nr_of_function_types < 128);
262
+ self.output.push(nr_of_function_types);
263
+
264
+ for i in 0..(nr_of_function_types) {
265
+ match FunctionType::of_u8(i) {
266
+ FunctionType::FN0 => {
267
+ self.output.push(op::TYPE_FUNC);
268
+ self.output.push(0); // no args
269
+ self.output.push(0); // no return val
270
+ },
271
+ FunctionType::FN1 => {
272
+ self.output.push(op::TYPE_FUNC);
273
+ self.output.push(1);
274
+ self.output.push(op::TYPE_I32);
275
+ self.output.push(0);
276
+ },
277
+ FunctionType::FN2 => {
278
+ self.output.push(op::TYPE_FUNC);
279
+ self.output.push(2);
280
+ self.output.push(op::TYPE_I32);
281
+ self.output.push(op::TYPE_I32);
282
+ self.output.push(0);
283
+ },
284
+ FunctionType::FN3 => {
285
+ self.output.push(op::TYPE_FUNC);
286
+ self.output.push(3);
287
+ self.output.push(op::TYPE_I32);
288
+ self.output.push(op::TYPE_I32);
289
+ self.output.push(op::TYPE_I32);
290
+ self.output.push(0);
291
+ },
292
+ FunctionType::FN0_RET => {
293
+ self.output.push(op::TYPE_FUNC);
294
+ self.output.push(0);
295
+ self.output.push(1);
296
+ self.output.push(op::TYPE_I32);
297
+ },
298
+ FunctionType::FN0_RET_I64 => {
299
+ self.output.push(op::TYPE_FUNC);
300
+ self.output.push(0);
301
+ self.output.push(1);
302
+ self.output.push(op::TYPE_I64);
303
+ },
304
+ FunctionType::FN1_RET => {
305
+ self.output.push(op::TYPE_FUNC);
306
+ self.output.push(1);
307
+ self.output.push(op::TYPE_I32);
308
+ self.output.push(1);
309
+ self.output.push(op::TYPE_I32);
310
+ },
311
+ FunctionType::FN2_RET => {
312
+ self.output.push(op::TYPE_FUNC);
313
+ self.output.push(2);
314
+ self.output.push(op::TYPE_I32);
315
+ self.output.push(op::TYPE_I32);
316
+ self.output.push(1);
317
+ self.output.push(op::TYPE_I32);
318
+ },
319
+ FunctionType::FN1_RET_I64 => {
320
+ self.output.push(op::TYPE_FUNC);
321
+ self.output.push(1);
322
+ self.output.push(op::TYPE_I32);
323
+ self.output.push(1);
324
+ self.output.push(op::TYPE_I64);
325
+ },
326
+ FunctionType::FN1_F32_RET => {
327
+ self.output.push(op::TYPE_FUNC);
328
+ self.output.push(1);
329
+ self.output.push(op::TYPE_F32);
330
+ self.output.push(1);
331
+ self.output.push(op::TYPE_I32);
332
+ },
333
+ FunctionType::FN1_F64_RET => {
334
+ self.output.push(op::TYPE_FUNC);
335
+ self.output.push(1);
336
+ self.output.push(op::TYPE_F64);
337
+ self.output.push(1);
338
+ self.output.push(op::TYPE_I32);
339
+ },
340
+ FunctionType::FN2_I32_I64 => {
341
+ self.output.push(op::TYPE_FUNC);
342
+ self.output.push(2);
343
+ self.output.push(op::TYPE_I32);
344
+ self.output.push(op::TYPE_I64);
345
+ self.output.push(0);
346
+ },
347
+ FunctionType::FN2_I64_I32 => {
348
+ self.output.push(op::TYPE_FUNC);
349
+ self.output.push(2);
350
+ self.output.push(op::TYPE_I64);
351
+ self.output.push(op::TYPE_I32);
352
+ self.output.push(0);
353
+ },
354
+ FunctionType::FN2_I64_I32_RET => {
355
+ self.output.push(op::TYPE_FUNC);
356
+ self.output.push(2);
357
+ self.output.push(op::TYPE_I64);
358
+ self.output.push(op::TYPE_I32);
359
+ self.output.push(1);
360
+ self.output.push(op::TYPE_I32);
361
+ },
362
+ FunctionType::FN2_I64_I32_RET_I64 => {
363
+ self.output.push(op::TYPE_FUNC);
364
+ self.output.push(2);
365
+ self.output.push(op::TYPE_I64);
366
+ self.output.push(op::TYPE_I32);
367
+ self.output.push(1);
368
+ self.output.push(op::TYPE_I64);
369
+ },
370
+ FunctionType::FN2_F32_I32 => {
371
+ self.output.push(op::TYPE_FUNC);
372
+ self.output.push(2);
373
+ self.output.push(op::TYPE_F32);
374
+ self.output.push(op::TYPE_I32);
375
+ self.output.push(0);
376
+ },
377
+ FunctionType::FN3_RET => {
378
+ self.output.push(op::TYPE_FUNC);
379
+ self.output.push(3);
380
+ self.output.push(op::TYPE_I32);
381
+ self.output.push(op::TYPE_I32);
382
+ self.output.push(op::TYPE_I32);
383
+ self.output.push(1);
384
+ self.output.push(op::TYPE_I32);
385
+ },
386
+ FunctionType::FN3_I64_I32_I32 => {
387
+ self.output.push(op::TYPE_FUNC);
388
+ self.output.push(3);
389
+ self.output.push(op::TYPE_I64);
390
+ self.output.push(op::TYPE_I32);
391
+ self.output.push(op::TYPE_I32);
392
+ self.output.push(0);
393
+ },
394
+ FunctionType::FN3_I32_I64_I32 => {
395
+ self.output.push(op::TYPE_FUNC);
396
+ self.output.push(3);
397
+ self.output.push(op::TYPE_I32);
398
+ self.output.push(op::TYPE_I64);
399
+ self.output.push(op::TYPE_I32);
400
+ self.output.push(0);
401
+ },
402
+ FunctionType::FN3_I32_I64_I32_RET => {
403
+ self.output.push(op::TYPE_FUNC);
404
+ self.output.push(3);
405
+ self.output.push(op::TYPE_I32);
406
+ self.output.push(op::TYPE_I64);
407
+ self.output.push(op::TYPE_I32);
408
+ self.output.push(1);
409
+ self.output.push(op::TYPE_I32);
410
+ },
411
+ FunctionType::FN4_I32_I64_I64_I32_RET => {
412
+ self.output.push(op::TYPE_FUNC);
413
+ self.output.push(4);
414
+ self.output.push(op::TYPE_I32);
415
+ self.output.push(op::TYPE_I64);
416
+ self.output.push(op::TYPE_I64);
417
+ self.output.push(op::TYPE_I32);
418
+ self.output.push(1);
419
+ self.output.push(op::TYPE_I32);
420
+ },
421
+ }
422
+ }
423
+
424
+ let new_len = self.output.len();
425
+ let size = (new_len - 2) - idx_section_size;
426
+ write_fixed_leb16_at_idx(&mut self.output, idx_section_size, size.safe_to_u16());
427
+ }
428
+
429
+ /// Goes over the import block to find index of an import entry by function name
430
+ pub fn get_import_index(&self, fn_name: &str) -> Option<u16> {
431
+ let mut offset = self.idx_import_entries;
432
+ for i in 0..self.import_count {
433
+ offset += 1; // skip length of module name
434
+ offset += 1; // skip module name itself
435
+ let len = self.output[offset] as usize;
436
+ offset += 1;
437
+ let name = self
438
+ .output
439
+ .get(offset..(offset + len))
440
+ .expect("get function name");
441
+ if name == fn_name.as_bytes() {
442
+ return Some(i);
443
+ }
444
+ offset += len; // skip the string
445
+ offset += 1; // skip import kind
446
+ offset += 1; // skip type index
447
+ }
448
+ None
449
+ }
450
+
451
+ pub fn set_import_count(&mut self, count: u16) {
452
+ dbg_assert!(count < 0x4000);
453
+ self.import_count = count;
454
+ let idx_import_count = self.idx_import_count;
455
+ write_fixed_leb16_at_idx(&mut self.output, idx_import_count, count);
456
+ }
457
+
458
+ pub fn set_import_table_size(&mut self, size: usize) {
459
+ dbg_assert!(size < 0x4000);
460
+ self.import_table_size = size;
461
+ let idx_import_table_size = self.idx_import_table_size;
462
+ write_fixed_leb16_at_idx(&mut self.output, idx_import_table_size, size.safe_to_u16());
463
+ }
464
+
465
+ pub fn write_import_section_preamble(&mut self) {
466
+ self.output.push(op::SC_IMPORT);
467
+
468
+ self.idx_import_table_size = self.output.len();
469
+ self.output.push(1 | 0b10000000);
470
+ self.output.push(2); // 2 in 2 byte leb
471
+
472
+ self.idx_import_count = self.output.len();
473
+ self.output.push(1 | 0b10000000);
474
+ self.output.push(0); // 0 in 2 byte leb
475
+
476
+ // here after starts the actual list of imports
477
+ self.idx_import_entries = self.output.len();
478
+ }
479
+
480
+ pub fn write_memory_import(&mut self) {
481
+ self.output.push(1);
482
+ self.output.push('e' as u8);
483
+ self.output.push(1);
484
+ self.output.push('m' as u8);
485
+
486
+ self.output.push(op::EXT_MEMORY);
487
+
488
+ self.output.push(0); // memory flag, 0 for no maximum memory limit present
489
+ write_leb_u32(&mut self.output, 64); // initial memory length of 64 pages, takes 1 bytes in leb128
490
+
491
+ let new_import_count = self.import_count + 1;
492
+ self.set_import_count(new_import_count);
493
+
494
+ let new_table_size = self.import_table_size + 7;
495
+ self.set_import_table_size(new_table_size);
496
+ }
497
+
498
+ fn write_import_entry(&mut self, fn_name: &str, type_index: FunctionType) -> u16 {
499
+ self.output.push(1); // length of module name
500
+ self.output.push('e' as u8); // module name
501
+ self.output.push(fn_name.len().safe_to_u8());
502
+ self.output.extend(fn_name.as_bytes());
503
+ self.output.push(op::EXT_FUNCTION);
504
+ self.output.push(type_index.to_u8());
505
+
506
+ let new_import_count = self.import_count + 1;
507
+ self.set_import_count(new_import_count);
508
+
509
+ let new_table_size = self.import_table_size + 1 + 1 + 1 + fn_name.len() + 1 + 1;
510
+ self.set_import_table_size(new_table_size);
511
+
512
+ self.import_count - 1
513
+ }
514
+
515
+ pub fn write_function_section(&mut self) {
516
+ self.output.push(op::SC_FUNCTION);
517
+ self.output.push(2); // length of this section
518
+ self.output.push(1); // count of signature indices
519
+ self.output.push(FunctionType::FN1.to_u8());
520
+ }
521
+
522
+ pub fn write_export_section(&mut self) {
523
+ self.output.push(op::SC_EXPORT);
524
+ self.output.push(1 + 1 + 1 + 1 + 2); // size of this section
525
+ self.output.push(1); // count of table: just one function exported
526
+
527
+ self.output.push(1); // length of exported function name
528
+ self.output.push('f' as u8); // function name
529
+ self.output.push(op::EXT_FUNCTION);
530
+
531
+ // index of the exported function
532
+ // function space starts with imports. index of last import is import count - 1
533
+ // the last import however is a memory, so we subtract one from that
534
+ let next_op_idx = self.output.len();
535
+ self.output.push(0);
536
+ self.output.push(0); // add 2 bytes for writing 16 byte val
537
+ write_fixed_leb16_at_idx(&mut self.output, next_op_idx, self.import_count - 1);
538
+ }
539
+
540
+ fn get_fn_idx(&mut self, fn_name: &str, type_index: FunctionType) -> u16 {
541
+ match self.get_import_index(fn_name) {
542
+ Some(idx) => idx,
543
+ None => {
544
+ let idx = self.write_import_entry(fn_name, type_index);
545
+ idx
546
+ },
547
+ }
548
+ }
549
+
550
+ pub fn get_output_ptr(&self) -> *const u8 { self.output.as_ptr() }
551
+ pub fn get_output_len(&self) -> u32 { self.output.len() as u32 }
552
+
553
+ fn open_block(&mut self) -> Label {
554
+ let label = self.next_label;
555
+ self.next_label = self.next_label.next();
556
+ self.label_to_depth
557
+ .insert(label, self.label_stack.len() + 1);
558
+ self.label_stack.push(label);
559
+ label
560
+ }
561
+ fn close_block(&mut self) {
562
+ let label = self.label_stack.pop().unwrap();
563
+ let old_depth = self.label_to_depth.remove(&label).unwrap();
564
+ dbg_assert!(self.label_to_depth.len() + 1 == old_depth);
565
+ }
566
+
567
+ #[must_use = "local allocated but not used"]
568
+ fn alloc_local(&mut self) -> WasmLocal {
569
+ match self.free_locals_i32.pop() {
570
+ Some(local) => local,
571
+ None => {
572
+ let new_idx = self.local_count + WASM_MODULE_ARGUMENT_COUNT;
573
+ self.local_count = self.local_count.checked_add(1).unwrap();
574
+ WasmLocal(new_idx)
575
+ },
576
+ }
577
+ }
578
+ pub fn free_local(&mut self, local: WasmLocal) {
579
+ dbg_assert!(
580
+ (WASM_MODULE_ARGUMENT_COUNT..self.local_count + WASM_MODULE_ARGUMENT_COUNT)
581
+ .contains(&local.0)
582
+ );
583
+ self.free_locals_i32.push(local)
584
+ }
585
+
586
+ #[must_use = "local allocated but not used"]
587
+ pub fn set_new_local(&mut self) -> WasmLocal {
588
+ let local = self.alloc_local();
589
+ self.instruction_body.push(op::OP_SETLOCAL);
590
+ self.instruction_body.push(local.idx());
591
+ local
592
+ }
593
+ #[must_use = "local allocated but not used"]
594
+ pub fn tee_new_local(&mut self) -> WasmLocal {
595
+ let local = self.alloc_local();
596
+ self.instruction_body.push(op::OP_TEELOCAL);
597
+ self.instruction_body.push(local.idx());
598
+ local
599
+ }
600
+ pub fn set_local(&mut self, local: &WasmLocal) {
601
+ self.instruction_body.push(op::OP_SETLOCAL);
602
+ self.instruction_body.push(local.idx());
603
+ }
604
+ pub fn tee_local(&mut self, local: &WasmLocal) {
605
+ self.instruction_body.push(op::OP_TEELOCAL);
606
+ self.instruction_body.push(local.idx());
607
+ }
608
+ pub fn get_local(&mut self, local: &WasmLocal) {
609
+ self.instruction_body.push(op::OP_GETLOCAL);
610
+ self.instruction_body.push(local.idx());
611
+ }
612
+
613
+ #[must_use = "local allocated but not used"]
614
+ fn alloc_local_i64(&mut self) -> WasmLocalI64 {
615
+ match self.free_locals_i64.pop() {
616
+ Some(local) => local,
617
+ None => {
618
+ let new_idx = self.local_count + WASM_MODULE_ARGUMENT_COUNT;
619
+ self.local_count += 1;
620
+ WasmLocalI64(new_idx)
621
+ },
622
+ }
623
+ }
624
+ pub fn free_local_i64(&mut self, local: WasmLocalI64) {
625
+ dbg_assert!(
626
+ (WASM_MODULE_ARGUMENT_COUNT..self.local_count + WASM_MODULE_ARGUMENT_COUNT)
627
+ .contains(&local.0)
628
+ );
629
+ self.free_locals_i64.push(local)
630
+ }
631
+ #[must_use = "local allocated but not used"]
632
+ pub fn set_new_local_i64(&mut self) -> WasmLocalI64 {
633
+ let local = self.alloc_local_i64();
634
+ self.instruction_body.push(op::OP_SETLOCAL);
635
+ self.instruction_body.push(local.idx());
636
+ local
637
+ }
638
+ #[must_use = "local allocated but not used"]
639
+ pub fn tee_new_local_i64(&mut self) -> WasmLocalI64 {
640
+ let local = self.alloc_local_i64();
641
+ self.instruction_body.push(op::OP_TEELOCAL);
642
+ self.instruction_body.push(local.idx());
643
+ local
644
+ }
645
+ pub fn get_local_i64(&mut self, local: &WasmLocalI64) {
646
+ self.instruction_body.push(op::OP_GETLOCAL);
647
+ self.instruction_body.push(local.idx());
648
+ }
649
+
650
+ pub fn const_i32(&mut self, v: i32) {
651
+ self.instruction_body.push(op::OP_I32CONST);
652
+ write_leb_i32(&mut self.instruction_body, v);
653
+ }
654
+ pub fn const_i64(&mut self, v: i64) {
655
+ self.instruction_body.push(op::OP_I64CONST);
656
+ write_leb_i64(&mut self.instruction_body, v);
657
+ }
658
+
659
+ pub fn load_fixed_u8(&mut self, addr: u32) {
660
+ self.const_i32(addr as i32);
661
+ self.load_u8(0);
662
+ }
663
+ pub fn load_fixed_u16(&mut self, addr: u32) {
664
+ // doesn't cause a failure in the generated code, but it will be much slower
665
+ dbg_assert!((addr & 1) == 0);
666
+
667
+ self.const_i32(addr as i32);
668
+ self.instruction_body.push(op::OP_I32LOAD16U);
669
+ self.instruction_body.push(op::MEM_ALIGN16);
670
+ self.instruction_body.push(0); // immediate offset
671
+ }
672
+ pub fn load_fixed_i32(&mut self, addr: u32) {
673
+ // doesn't cause a failure in the generated code, but it will be much slower
674
+ dbg_assert!((addr & 3) == 0);
675
+
676
+ self.const_i32(addr as i32);
677
+ self.load_aligned_i32(0);
678
+ }
679
+ pub fn load_fixed_i64(&mut self, addr: u32) {
680
+ // doesn't cause a failure in the generated code, but it will be much slower
681
+ dbg_assert!((addr & 7) == 0);
682
+
683
+ self.const_i32(addr as i32);
684
+ self.load_aligned_i64(0);
685
+ }
686
+
687
+ pub fn load_u8(&mut self, byte_offset: u32) {
688
+ self.instruction_body.push(op::OP_I32LOAD8U);
689
+ self.instruction_body.push(op::MEM_NO_ALIGN);
690
+ write_leb_u32(&mut self.instruction_body, byte_offset);
691
+ }
692
+
693
+ pub fn load_unaligned_i64(&mut self, byte_offset: u32) {
694
+ self.instruction_body.push(op::OP_I64LOAD);
695
+ self.instruction_body.push(op::MEM_NO_ALIGN);
696
+ write_leb_u32(&mut self.instruction_body, byte_offset);
697
+ }
698
+
699
+ pub fn load_unaligned_i32(&mut self, byte_offset: u32) {
700
+ self.instruction_body.push(op::OP_I32LOAD);
701
+ self.instruction_body.push(op::MEM_NO_ALIGN);
702
+ write_leb_u32(&mut self.instruction_body, byte_offset);
703
+ }
704
+
705
+ pub fn load_unaligned_u16(&mut self, byte_offset: u32) {
706
+ self.instruction_body.push(op::OP_I32LOAD16U);
707
+ self.instruction_body.push(op::MEM_NO_ALIGN);
708
+ write_leb_u32(&mut self.instruction_body, byte_offset);
709
+ }
710
+
711
+ pub fn load_aligned_f64(&mut self, byte_offset: u32) {
712
+ self.instruction_body.push(op::OP_F64LOAD);
713
+ self.instruction_body.push(op::MEM_ALIGN64);
714
+ write_leb_u32(&mut self.instruction_body, byte_offset);
715
+ }
716
+
717
+ pub fn load_aligned_i64(&mut self, byte_offset: u32) {
718
+ self.instruction_body.push(op::OP_I64LOAD);
719
+ self.instruction_body.push(op::MEM_ALIGN64);
720
+ write_leb_u32(&mut self.instruction_body, byte_offset);
721
+ }
722
+
723
+ pub fn load_aligned_f32(&mut self, byte_offset: u32) {
724
+ self.instruction_body.push(op::OP_F32LOAD);
725
+ self.instruction_body.push(op::MEM_ALIGN32);
726
+ write_leb_u32(&mut self.instruction_body, byte_offset);
727
+ }
728
+
729
+ pub fn load_aligned_i32(&mut self, byte_offset: u32) {
730
+ self.instruction_body.push(op::OP_I32LOAD);
731
+ self.instruction_body.push(op::MEM_ALIGN32);
732
+ write_leb_u32(&mut self.instruction_body, byte_offset);
733
+ }
734
+
735
+ pub fn load_aligned_u16(&mut self, byte_offset: u32) {
736
+ self.instruction_body.push(op::OP_I32LOAD16U);
737
+ self.instruction_body.push(op::MEM_ALIGN16);
738
+ write_leb_u32(&mut self.instruction_body, byte_offset);
739
+ }
740
+
741
+ pub fn store_u8(&mut self, byte_offset: u32) {
742
+ self.instruction_body.push(op::OP_I32STORE8);
743
+ self.instruction_body.push(op::MEM_NO_ALIGN);
744
+ write_leb_u32(&mut self.instruction_body, byte_offset);
745
+ }
746
+
747
+ pub fn store_aligned_u16(&mut self, byte_offset: u32) {
748
+ self.instruction_body.push(op::OP_I32STORE16);
749
+ self.instruction_body.push(op::MEM_ALIGN16);
750
+ write_leb_u32(&mut self.instruction_body, byte_offset);
751
+ }
752
+
753
+ pub fn store_aligned_i32(&mut self, byte_offset: u32) {
754
+ self.instruction_body.push(op::OP_I32STORE);
755
+ self.instruction_body.push(op::MEM_ALIGN32);
756
+ write_leb_u32(&mut self.instruction_body, byte_offset);
757
+ }
758
+
759
+ pub fn store_aligned_i64(&mut self, byte_offset: u32) {
760
+ self.instruction_body.push(op::OP_I64STORE);
761
+ self.instruction_body.push(op::MEM_ALIGN64);
762
+ write_leb_u32(&mut self.instruction_body, byte_offset);
763
+ }
764
+
765
+ pub fn store_unaligned_u16(&mut self, byte_offset: u32) {
766
+ self.instruction_body.push(op::OP_I32STORE16);
767
+ self.instruction_body.push(op::MEM_NO_ALIGN);
768
+ write_leb_u32(&mut self.instruction_body, byte_offset);
769
+ }
770
+
771
+ pub fn store_unaligned_i32(&mut self, byte_offset: u32) {
772
+ self.instruction_body.push(op::OP_I32STORE);
773
+ self.instruction_body.push(op::MEM_NO_ALIGN);
774
+ write_leb_u32(&mut self.instruction_body, byte_offset);
775
+ }
776
+
777
+ pub fn store_unaligned_i64(&mut self, byte_offset: u32) {
778
+ self.instruction_body.push(op::OP_I64STORE);
779
+ self.instruction_body.push(op::MEM_NO_ALIGN);
780
+ write_leb_u32(&mut self.instruction_body, byte_offset);
781
+ }
782
+
783
+ pub fn increment_fixed_i64(&mut self, byte_offset: u32, n: i64) {
784
+ self.const_i32(byte_offset as i32);
785
+ self.load_fixed_i64(byte_offset);
786
+ self.const_i64(n);
787
+ self.add_i64();
788
+ self.store_aligned_i64(0);
789
+ }
790
+
791
+ pub fn add_i32(&mut self) { self.instruction_body.push(op::OP_I32ADD); }
792
+ pub fn add_i64(&mut self) { self.instruction_body.push(op::OP_I64ADD); }
793
+ pub fn sub_i32(&mut self) { self.instruction_body.push(op::OP_I32SUB); }
794
+ pub fn and_i32(&mut self) { self.instruction_body.push(op::OP_I32AND); }
795
+ pub fn or_i32(&mut self) { self.instruction_body.push(op::OP_I32OR); }
796
+ pub fn or_i64(&mut self) { self.instruction_body.push(op::OP_I64OR); }
797
+ pub fn xor_i32(&mut self) { self.instruction_body.push(op::OP_I32XOR); }
798
+ pub fn mul_i32(&mut self) { self.instruction_body.push(op::OP_I32MUL); }
799
+ pub fn mul_i64(&mut self) { self.instruction_body.push(op::OP_I64MUL); }
800
+ pub fn div_i64(&mut self) { self.instruction_body.push(op::OP_I64DIVU); }
801
+ pub fn rem_i64(&mut self) { self.instruction_body.push(op::OP_I64REMU); }
802
+
803
+ pub fn rotl_i32(&mut self) { self.instruction_body.push(op::OP_I32ROTL); }
804
+
805
+ pub fn shl_i32(&mut self) { self.instruction_body.push(op::OP_I32SHL); }
806
+ pub fn shl_i64(&mut self) { self.instruction_body.push(op::OP_I64SHL); }
807
+ pub fn shr_u_i32(&mut self) { self.instruction_body.push(op::OP_I32SHRU); }
808
+ pub fn shr_u_i64(&mut self) { self.instruction_body.push(op::OP_I64SHRU); }
809
+ pub fn shr_s_i32(&mut self) { self.instruction_body.push(op::OP_I32SHRS); }
810
+
811
+ pub fn eq_i32(&mut self) { self.instruction_body.push(op::OP_I32EQ); }
812
+ pub fn eq_i64(&mut self) { self.instruction_body.push(op::OP_I64EQ); }
813
+ pub fn ne_i32(&mut self) { self.instruction_body.push(op::OP_I32NE); }
814
+ pub fn ne_i64(&mut self) { self.instruction_body.push(op::OP_I64NE); }
815
+
816
+ pub fn le_i32(&mut self) { self.instruction_body.push(op::OP_I32LES); }
817
+ pub fn lt_i32(&mut self) { self.instruction_body.push(op::OP_I32LTS); }
818
+ pub fn ge_i32(&mut self) { self.instruction_body.push(op::OP_I32GES); }
819
+ pub fn gt_i32(&mut self) { self.instruction_body.push(op::OP_I32GTS); }
820
+
821
+ pub fn gtu_i32(&mut self) { self.instruction_body.push(op::OP_I32GTU); }
822
+ pub fn geu_i32(&mut self) { self.instruction_body.push(op::OP_I32GEU); }
823
+ pub fn ltu_i32(&mut self) { self.instruction_body.push(op::OP_I32LTU); }
824
+ pub fn leu_i32(&mut self) { self.instruction_body.push(op::OP_I32LEU); }
825
+
826
+ pub fn gtu_i64(&mut self) { self.instruction_body.push(op::OP_I64GTU); }
827
+
828
+ pub fn reinterpret_i32_as_f32(&mut self) {
829
+ self.instruction_body.push(op::OP_F32REINTERPRETI32);
830
+ }
831
+ //pub fn reinterpret_f32_as_i32(&mut self) {
832
+ // self.instruction_body.push(op::OP_I32REINTERPRETF32);
833
+ //}
834
+ pub fn reinterpret_i64_as_f64(&mut self) {
835
+ self.instruction_body.push(op::OP_F64REINTERPRETI64);
836
+ }
837
+ //pub fn reinterpret_f64_as_i64(&mut self) {
838
+ // self.instruction_body.push(op::OP_I64REINTERPRETF64);
839
+ //}
840
+ //pub fn promote_f32_to_f64(&mut self) { self.instruction_body.push(op::OP_F64PROMOTEF32); }
841
+ //pub fn demote_f64_to_f32(&mut self) { self.instruction_body.push(op::OP_F32DEMOTEF64); }
842
+ //pub fn convert_i32_to_f64(&mut self) { self.instruction_body.push(op::OP_F64CONVERTSI32); }
843
+ //pub fn convert_i64_to_f64(&mut self) { self.instruction_body.push(op::OP_F64CONVERTSI64); }
844
+ pub fn extend_unsigned_i32_to_i64(&mut self) {
845
+ self.instruction_body.push(op::OP_I64EXTENDUI32);
846
+ }
847
+ pub fn extend_signed_i32_to_i64(&mut self) { self.instruction_body.push(op::OP_I64EXTENDSI32); }
848
+ pub fn wrap_i64_to_i32(&mut self) { self.instruction_body.push(op::OP_I32WRAPI64); }
849
+
850
+ pub fn eqz_i32(&mut self) { self.instruction_body.push(op::OP_I32EQZ); }
851
+
852
+ pub fn select(&mut self) { self.instruction_body.push(op::OP_SELECT); }
853
+
854
+ pub fn if_i32(&mut self) {
855
+ self.open_block();
856
+ self.instruction_body.push(op::OP_IF);
857
+ self.instruction_body.push(op::TYPE_I32);
858
+ }
859
+ #[allow(dead_code)]
860
+ pub fn if_i64(&mut self) {
861
+ self.open_block();
862
+ self.instruction_body.push(op::OP_IF);
863
+ self.instruction_body.push(op::TYPE_I64);
864
+ }
865
+ #[allow(dead_code)]
866
+ pub fn block_i32(&mut self) {
867
+ self.open_block();
868
+ self.instruction_body.push(op::OP_BLOCK);
869
+ self.instruction_body.push(op::TYPE_I32);
870
+ }
871
+
872
+ pub fn if_void(&mut self) {
873
+ self.open_block();
874
+ self.instruction_body.push(op::OP_IF);
875
+ self.instruction_body.push(op::TYPE_VOID_BLOCK);
876
+ }
877
+
878
+ pub fn else_(&mut self) {
879
+ dbg_assert!(!self.label_stack.is_empty());
880
+ self.instruction_body.push(op::OP_ELSE);
881
+ }
882
+
883
+ pub fn loop_void(&mut self) -> Label {
884
+ self.instruction_body.push(op::OP_LOOP);
885
+ self.instruction_body.push(op::TYPE_VOID_BLOCK);
886
+ self.open_block()
887
+ }
888
+
889
+ pub fn block_void(&mut self) -> Label {
890
+ self.instruction_body.push(op::OP_BLOCK);
891
+ self.instruction_body.push(op::TYPE_VOID_BLOCK);
892
+ self.open_block()
893
+ }
894
+
895
+ pub fn block_end(&mut self) {
896
+ self.close_block();
897
+ self.instruction_body.push(op::OP_END);
898
+ }
899
+
900
+ pub fn return_(&mut self) { self.instruction_body.push(op::OP_RETURN); }
901
+
902
+ #[allow(dead_code)]
903
+ pub fn drop_(&mut self) { self.instruction_body.push(op::OP_DROP); }
904
+
905
+ pub fn brtable(
906
+ &mut self,
907
+ default_case: Label,
908
+ cases: &mut dyn std::iter::ExactSizeIterator<Item = &Label>,
909
+ ) {
910
+ self.instruction_body.push(op::OP_BRTABLE);
911
+ write_leb_u32(&mut self.instruction_body, cases.len() as u32);
912
+ for case in cases {
913
+ self.write_label(*case);
914
+ }
915
+ self.write_label(default_case);
916
+ }
917
+
918
+ pub fn br(&mut self, label: Label) {
919
+ self.instruction_body.push(op::OP_BR);
920
+ self.write_label(label);
921
+ }
922
+ pub fn br_if(&mut self, label: Label) {
923
+ self.instruction_body.push(op::OP_BRIF);
924
+ self.write_label(label);
925
+ }
926
+
927
+ fn write_label(&mut self, label: Label) {
928
+ let depth = *self.label_to_depth.get(&label).unwrap();
929
+ dbg_assert!(depth <= self.label_stack.len());
930
+ write_leb_u32(
931
+ &mut self.instruction_body,
932
+ (self.label_stack.len() - depth) as u32,
933
+ );
934
+ }
935
+
936
+ fn call_fn(&mut self, name: &str, function: FunctionType) {
937
+ let i = self.get_fn_idx(name, function);
938
+ self.instruction_body.push(op::OP_CALL);
939
+ write_leb_u32(&mut self.instruction_body, i as u32);
940
+ }
941
+
942
+ pub fn call_fn0(&mut self, name: &str) { self.call_fn(name, FunctionType::FN0) }
943
+ pub fn call_fn0_ret(&mut self, name: &str) { self.call_fn(name, FunctionType::FN0_RET) }
944
+ pub fn call_fn0_ret_i64(&mut self, name: &str) { self.call_fn(name, FunctionType::FN0_RET_I64) }
945
+ pub fn call_fn1(&mut self, name: &str) { self.call_fn(name, FunctionType::FN1) }
946
+ pub fn call_fn1_ret(&mut self, name: &str) { self.call_fn(name, FunctionType::FN1_RET) }
947
+ pub fn call_fn1_ret_i64(&mut self, name: &str) { self.call_fn(name, FunctionType::FN1_RET_I64) }
948
+ pub fn call_fn1_f32_ret(&mut self, name: &str) { self.call_fn(name, FunctionType::FN1_F32_RET) }
949
+ pub fn call_fn1_f64_ret(&mut self, name: &str) { self.call_fn(name, FunctionType::FN1_F64_RET) }
950
+ pub fn call_fn2(&mut self, name: &str) { self.call_fn(name, FunctionType::FN2) }
951
+ pub fn call_fn2_i32_i64(&mut self, name: &str) { self.call_fn(name, FunctionType::FN2_I32_I64) }
952
+ pub fn call_fn2_i64_i32(&mut self, name: &str) { self.call_fn(name, FunctionType::FN2_I64_I32) }
953
+ pub fn call_fn2_i64_i32_ret(&mut self, name: &str) {
954
+ self.call_fn(name, FunctionType::FN2_I64_I32_RET)
955
+ }
956
+ pub fn call_fn2_i64_i32_ret_i64(&mut self, name: &str) {
957
+ self.call_fn(name, FunctionType::FN2_I64_I32_RET_I64)
958
+ }
959
+ pub fn call_fn2_f32_i32(&mut self, name: &str) { self.call_fn(name, FunctionType::FN2_F32_I32) }
960
+ pub fn call_fn2_ret(&mut self, name: &str) { self.call_fn(name, FunctionType::FN2_RET) }
961
+ pub fn call_fn3(&mut self, name: &str) { self.call_fn(name, FunctionType::FN3) }
962
+ pub fn call_fn3_ret(&mut self, name: &str) { self.call_fn(name, FunctionType::FN3_RET) }
963
+ pub fn call_fn3_i64_i32_i32(&mut self, name: &str) {
964
+ self.call_fn(name, FunctionType::FN3_I64_I32_I32)
965
+ }
966
+ pub fn call_fn3_i32_i64_i32(&mut self, name: &str) {
967
+ self.call_fn(name, FunctionType::FN3_I32_I64_I32)
968
+ }
969
+ pub fn call_fn3_i32_i64_i32_ret(&mut self, name: &str) {
970
+ self.call_fn(name, FunctionType::FN3_I32_I64_I32_RET)
971
+ }
972
+ pub fn call_fn4_i32_i64_i64_i32_ret(&mut self, name: &str) {
973
+ self.call_fn(name, FunctionType::FN4_I32_I64_I64_I32_RET)
974
+ }
975
+
976
+ pub fn unreachable(&mut self) { self.instruction_body.push(op::OP_UNREACHABLE) }
977
+
978
+ pub fn instruction_body_length(&self) -> u32 { self.instruction_body.len() as u32 }
979
+ }
980
+
981
+ #[cfg(test)]
982
+ mod tests {
983
+ use super::{FunctionType, WasmBuilder, WASM_MODULE_ARGUMENT_COUNT};
984
+ use std::fs::File;
985
+ use std::io::Write;
986
+
987
+ #[test]
988
+ fn import_table_management() {
989
+ let mut w = WasmBuilder::new();
990
+
991
+ assert_eq!(0, w.get_fn_idx("foo", FunctionType::FN0));
992
+ assert_eq!(1, w.get_fn_idx("bar", FunctionType::FN1));
993
+ assert_eq!(0, w.get_fn_idx("foo", FunctionType::FN0));
994
+ assert_eq!(2, w.get_fn_idx("baz", FunctionType::FN2));
995
+ }
996
+
997
+ #[test]
998
+ fn builder_test() {
999
+ let mut m = WasmBuilder::new();
1000
+
1001
+ m.call_fn("foo", FunctionType::FN0);
1002
+ m.call_fn("bar", FunctionType::FN0);
1003
+
1004
+ let local0 = m.alloc_local(); // for ensuring that reset clears previous locals
1005
+ m.free_local(local0);
1006
+
1007
+ m.finish();
1008
+ m.reset();
1009
+
1010
+ m.const_i32(2);
1011
+
1012
+ m.call_fn("baz", FunctionType::FN1_RET);
1013
+ m.call_fn("foo", FunctionType::FN1);
1014
+
1015
+ m.const_i32(10);
1016
+ let local1 = m.alloc_local();
1017
+ m.tee_local(&local1); // local1 = 10
1018
+
1019
+ m.const_i32(20);
1020
+ m.add_i32();
1021
+ let local2 = m.alloc_local();
1022
+ m.tee_local(&local2); // local2 = 30
1023
+
1024
+ m.free_local(local1);
1025
+
1026
+ let local3 = m.alloc_local();
1027
+ assert_eq!(local3.idx(), WASM_MODULE_ARGUMENT_COUNT);
1028
+
1029
+ m.free_local(local2);
1030
+ m.free_local(local3);
1031
+
1032
+ m.const_i32(30);
1033
+ m.ne_i32();
1034
+ m.if_void();
1035
+ m.unreachable();
1036
+ m.block_end();
1037
+
1038
+ m.finish();
1039
+
1040
+ let op_ptr = m.get_output_ptr();
1041
+ let op_len = m.get_output_len();
1042
+ dbg_log!("op_ptr: {:?}, op_len: {:?}", op_ptr, op_len);
1043
+
1044
+ let mut f = File::create("build/dummy_output.wasm").expect("creating dummy_output.wasm");
1045
+ f.write_all(&m.output).expect("write dummy_output.wasm");
1046
+ }
1047
+ }