@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.
- package/LICENSE +22 -0
- package/LICENSE.MIT +22 -0
- package/Readme.md +237 -0
- package/dist/v86.browser.js +26666 -0
- package/dist/v86.browser.js.map +7 -0
- package/dist/v86.js +26632 -0
- package/dist/v86.js.map +7 -0
- package/gen/generate_analyzer.ts +512 -0
- package/gen/generate_interpreter.ts +522 -0
- package/gen/generate_jit.ts +624 -0
- package/gen/rust_ast.ts +107 -0
- package/gen/util.ts +35 -0
- package/gen/x86_table.ts +1836 -0
- package/lib/9p.ts +1547 -0
- package/lib/filesystem.ts +1879 -0
- package/lib/marshall.ts +168 -0
- package/lib/softfloat/softfloat.c +32501 -0
- package/lib/zstd/zstddeclib.c +13520 -0
- package/package.json +75 -0
- package/src/acpi.ts +267 -0
- package/src/browser/dummy_screen.ts +106 -0
- package/src/browser/fake_network.ts +1771 -0
- package/src/browser/fetch_network.ts +361 -0
- package/src/browser/filestorage.ts +124 -0
- package/src/browser/inbrowser_network.ts +57 -0
- package/src/browser/keyboard.ts +564 -0
- package/src/browser/main.ts +3415 -0
- package/src/browser/mouse.ts +255 -0
- package/src/browser/network.ts +142 -0
- package/src/browser/print_stats.ts +336 -0
- package/src/browser/screen.ts +978 -0
- package/src/browser/serial.ts +316 -0
- package/src/browser/speaker.ts +1223 -0
- package/src/browser/starter.ts +1688 -0
- package/src/browser/wisp_network.ts +332 -0
- package/src/browser/worker_bus.ts +64 -0
- package/src/buffer.ts +652 -0
- package/src/bus.ts +78 -0
- package/src/const.ts +128 -0
- package/src/cpu.ts +2891 -0
- package/src/dma.ts +474 -0
- package/src/elf.ts +251 -0
- package/src/floppy.ts +1778 -0
- package/src/ide.ts +3455 -0
- package/src/io.ts +504 -0
- package/src/iso9660.ts +317 -0
- package/src/kernel.ts +250 -0
- package/src/lib.ts +645 -0
- package/src/log.ts +149 -0
- package/src/main.ts +199 -0
- package/src/ne2k.ts +1589 -0
- package/src/pci.ts +815 -0
- package/src/pit.ts +406 -0
- package/src/ps2.ts +820 -0
- package/src/rtc.ts +537 -0
- package/src/rust/analysis.rs +101 -0
- package/src/rust/codegen.rs +2660 -0
- package/src/rust/config.rs +3 -0
- package/src/rust/control_flow.rs +425 -0
- package/src/rust/cpu/apic.rs +658 -0
- package/src/rust/cpu/arith.rs +1207 -0
- package/src/rust/cpu/call_indirect.rs +2 -0
- package/src/rust/cpu/cpu.rs +4501 -0
- package/src/rust/cpu/fpu.rs +923 -0
- package/src/rust/cpu/global_pointers.rs +112 -0
- package/src/rust/cpu/instructions.rs +2486 -0
- package/src/rust/cpu/instructions_0f.rs +5261 -0
- package/src/rust/cpu/ioapic.rs +316 -0
- package/src/rust/cpu/memory.rs +351 -0
- package/src/rust/cpu/misc_instr.rs +613 -0
- package/src/rust/cpu/mod.rs +16 -0
- package/src/rust/cpu/modrm.rs +133 -0
- package/src/rust/cpu/pic.rs +402 -0
- package/src/rust/cpu/sse_instr.rs +361 -0
- package/src/rust/cpu/string.rs +701 -0
- package/src/rust/cpu/vga.rs +175 -0
- package/src/rust/cpu_context.rs +69 -0
- package/src/rust/dbg.rs +98 -0
- package/src/rust/gen/analyzer.rs +3807 -0
- package/src/rust/gen/analyzer0f.rs +3992 -0
- package/src/rust/gen/interpreter.rs +4447 -0
- package/src/rust/gen/interpreter0f.rs +5404 -0
- package/src/rust/gen/jit.rs +5080 -0
- package/src/rust/gen/jit0f.rs +5547 -0
- package/src/rust/gen/mod.rs +14 -0
- package/src/rust/jit.rs +2443 -0
- package/src/rust/jit_instructions.rs +7881 -0
- package/src/rust/js_api.rs +6 -0
- package/src/rust/leb.rs +46 -0
- package/src/rust/lib.rs +29 -0
- package/src/rust/modrm.rs +330 -0
- package/src/rust/opstats.rs +249 -0
- package/src/rust/page.rs +15 -0
- package/src/rust/paging.rs +25 -0
- package/src/rust/prefix.rs +15 -0
- package/src/rust/profiler.rs +155 -0
- package/src/rust/regs.rs +38 -0
- package/src/rust/softfloat.rs +286 -0
- package/src/rust/state_flags.rs +27 -0
- package/src/rust/wasmgen/mod.rs +2 -0
- package/src/rust/wasmgen/wasm_builder.rs +1047 -0
- package/src/rust/wasmgen/wasm_opcodes.rs +221 -0
- package/src/rust/zstd.rs +105 -0
- package/src/sb16.ts +1928 -0
- package/src/state.ts +359 -0
- package/src/uart.ts +472 -0
- package/src/vga.ts +2791 -0
- package/src/virtio.ts +1756 -0
- package/src/virtio_balloon.ts +273 -0
- package/src/virtio_console.ts +372 -0
- 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
|
+
}
|