@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,3 @@
1
+ pub const LOG_PAGE_FAULTS: bool = false;
2
+
3
+ pub const VMWARE_HYPERVISOR_PORT: bool = true;
@@ -0,0 +1,425 @@
1
+ use std::collections::HashSet;
2
+ use std::collections::{BTreeMap, BTreeSet};
3
+ use std::iter;
4
+
5
+ use crate::jit::{BasicBlock, BasicBlockType, MAX_EXTRA_BASIC_BLOCKS};
6
+ use crate::profiler;
7
+
8
+ const ENTRY_NODE_ID: u32 = 0xffff_ffff;
9
+
10
+ // this code works fine with either BTree or Hash Maps/Sets
11
+ // - HashMap / HashSet: slightly faster
12
+ // - BTreeMap / BTreeSet: stable iteration order (graphs don't change between rust versions, required for expect tests)
13
+ type Set = BTreeSet<u32>;
14
+ type Graph = BTreeMap<u32, Set>;
15
+
16
+ /// Reverse the direction of all edges in the graph
17
+ fn rev_graph_edges(nodes: &Graph) -> Graph {
18
+ let mut rev_nodes = Graph::new();
19
+ for (from, tos) in nodes {
20
+ for to in tos {
21
+ rev_nodes
22
+ .entry(*to)
23
+ .or_insert_with(|| Set::new())
24
+ .insert(*from);
25
+ }
26
+ }
27
+ rev_nodes
28
+ }
29
+
30
+ pub fn make_graph(basic_blocks: &Vec<BasicBlock>) -> Graph {
31
+ let mut nodes = Graph::new();
32
+ let mut entry_edges = Set::new();
33
+
34
+ for b in basic_blocks.iter() {
35
+ let mut edges = Set::new();
36
+
37
+ match &b.ty {
38
+ &BasicBlockType::ConditionalJump {
39
+ next_block_addr,
40
+ next_block_branch_taken_addr,
41
+ ..
42
+ } => {
43
+ if let Some(next_block_addr) = next_block_addr {
44
+ edges.insert(next_block_addr);
45
+ }
46
+ if let Some(next_block_branch_taken_addr) = next_block_branch_taken_addr {
47
+ edges.insert(next_block_branch_taken_addr);
48
+ }
49
+ },
50
+ &BasicBlockType::Normal {
51
+ next_block_addr: Some(next_block_addr),
52
+ ..
53
+ } => {
54
+ edges.insert(next_block_addr);
55
+ },
56
+ &BasicBlockType::Normal {
57
+ next_block_addr: None,
58
+ ..
59
+ } => {},
60
+ BasicBlockType::Exit => {},
61
+ BasicBlockType::AbsoluteEip => {
62
+ // Not necessary: We generate a loop around the outer brtable unconditionally
63
+ //edges.insert(ENTRY_NODE_ID);
64
+ },
65
+ }
66
+
67
+ nodes.insert(b.addr, edges);
68
+
69
+ if b.is_entry_block {
70
+ entry_edges.insert(b.addr);
71
+ }
72
+ }
73
+
74
+ // Entry node that represents the initial basic block of the generated function (must be
75
+ // able to reach all entry nodes)
76
+ nodes.insert(ENTRY_NODE_ID, entry_edges);
77
+ return nodes;
78
+ }
79
+
80
+ pub enum WasmStructure {
81
+ BasicBlock(u32),
82
+ Dispatcher(Vec<u32>),
83
+ Loop(Vec<WasmStructure>),
84
+ Block(Vec<WasmStructure>),
85
+ }
86
+ impl WasmStructure {
87
+ pub fn print(&self, depth: usize) {
88
+ match self {
89
+ Self::BasicBlock(addr) => {
90
+ dbg_log!("{} 0x{:x}", " ".repeat(depth), addr);
91
+ },
92
+ Self::Dispatcher(entries) => {
93
+ dbg_log!("{} Dispatcher entries:", " ".repeat(depth));
94
+ for e in entries {
95
+ dbg_log!("{} {:x}", " ".repeat(depth), e);
96
+ }
97
+ },
98
+ Self::Loop(elements) => {
99
+ dbg_log!("{} loop_void({})", " ".repeat(depth), elements.len());
100
+ for e in elements {
101
+ e.print(depth + 1)
102
+ }
103
+ dbg_log!("{} loop_end({})", " ".repeat(depth), elements.len());
104
+ },
105
+ Self::Block(elements) => {
106
+ dbg_log!("{} block_void({})", " ".repeat(depth), elements.len());
107
+ for e in elements {
108
+ e.print(depth + 1)
109
+ }
110
+ dbg_log!("{} block_end({})", " ".repeat(depth), elements.len());
111
+ },
112
+ }
113
+ }
114
+
115
+ fn branches(&self, edges: &Graph) -> HashSet<u32> {
116
+ fn handle(block: &WasmStructure, edges: &Graph, result: &mut HashSet<u32>) {
117
+ match block {
118
+ WasmStructure::BasicBlock(addr) => result.extend(edges.get(&addr).unwrap()),
119
+ WasmStructure::Dispatcher(entries) => result.extend(entries),
120
+ WasmStructure::Loop(children) | WasmStructure::Block(children) => {
121
+ for c in children.iter() {
122
+ handle(c, edges, result);
123
+ }
124
+ },
125
+ }
126
+ }
127
+
128
+ let mut result = HashSet::new();
129
+ handle(self, edges, &mut result);
130
+ result
131
+ }
132
+
133
+ pub fn head(&self) -> Box<dyn iter::Iterator<Item = u32> + '_> {
134
+ match self {
135
+ Self::BasicBlock(addr) => Box::new(iter::once(*addr)),
136
+ Self::Dispatcher(entries) => Box::new(entries.iter().copied()),
137
+ Self::Loop(children) => children.first().unwrap().head(),
138
+ Self::Block(elements) => elements.first().unwrap().head(),
139
+ }
140
+ }
141
+ }
142
+
143
+ /// Check:
144
+ /// - Dispatcher appears at the beginning of a loop
145
+ /// - No two nested blocks at the end
146
+ /// - No two nested loops at the beginning
147
+ /// - No empty blocks or loops
148
+ /// - The entry node block is not present
149
+ pub fn assert_invariants(blocks: &Vec<WasmStructure>) {
150
+ fn check(node: &WasmStructure, in_tail_block: bool, in_head_loop: bool, is_first: bool) {
151
+ match node {
152
+ WasmStructure::Block(children) => {
153
+ dbg_assert!(!in_tail_block);
154
+ dbg_assert!(!children.is_empty());
155
+ for (i, c) in children.iter().enumerate() {
156
+ let is_first = i == 0;
157
+ let is_last = i == children.len() - 1;
158
+ check(c, is_last, in_head_loop && is_first, is_first);
159
+ }
160
+ },
161
+ WasmStructure::Loop(children) => {
162
+ dbg_assert!(!in_head_loop);
163
+ dbg_assert!(!children.is_empty());
164
+ for (i, c) in children.iter().enumerate() {
165
+ let is_first = i == 0;
166
+ let is_last = i == children.len() - 1;
167
+ check(c, in_tail_block && is_last, is_first, is_first);
168
+ }
169
+ },
170
+ &WasmStructure::BasicBlock(addr) => {
171
+ dbg_assert!(addr != ENTRY_NODE_ID);
172
+ },
173
+ WasmStructure::Dispatcher(_) => {
174
+ dbg_assert!(is_first);
175
+ //dbg_assert!(in_head_loop); // fails for module dispatcher
176
+ },
177
+ }
178
+ }
179
+
180
+ for (i, b) in blocks.iter().enumerate() {
181
+ check(b, false, false, i == 0);
182
+ }
183
+ }
184
+
185
+ /// Strongly connected components via Kosaraju's algorithm
186
+ fn scc(edges: &Graph, rev_edges: &Graph) -> Vec<Vec<u32>> {
187
+ fn visit(
188
+ node: u32,
189
+ edges: &Graph,
190
+ rev_edges: &Graph,
191
+ visited: &mut HashSet<u32>,
192
+ l: &mut Vec<u32>,
193
+ ) {
194
+ if visited.contains(&node) {
195
+ return;
196
+ }
197
+ visited.insert(node);
198
+ for &next in edges.get(&node).unwrap() {
199
+ visit(next, edges, rev_edges, visited, l);
200
+ }
201
+ l.push(node);
202
+ }
203
+
204
+ let mut l = Vec::new();
205
+ let mut visited = HashSet::new();
206
+ for &node in edges.keys() {
207
+ visit(node, edges, rev_edges, &mut visited, &mut l);
208
+ }
209
+
210
+ fn assign(
211
+ node: u32,
212
+ edges: &Graph,
213
+ rev_edges: &Graph,
214
+ assigned: &mut HashSet<u32>,
215
+ group: &mut Vec<u32>,
216
+ ) {
217
+ if assigned.contains(&node) {
218
+ return;
219
+ }
220
+ assigned.insert(node);
221
+ group.push(node);
222
+ if let Some(nexts) = rev_edges.get(&node) {
223
+ for &next in nexts {
224
+ assign(next, edges, rev_edges, assigned, group);
225
+ }
226
+ }
227
+ }
228
+ let mut assigned = HashSet::new();
229
+ let mut assignment = Vec::new();
230
+ for &node in l.iter().rev() {
231
+ let mut group = Vec::new();
232
+ assign(node, edges, rev_edges, &mut assigned, &mut group);
233
+ if !group.is_empty() {
234
+ assignment.push(group);
235
+ }
236
+ }
237
+
238
+ assignment
239
+ }
240
+
241
+ pub fn loopify(nodes: &Graph) -> Vec<WasmStructure> {
242
+ let rev_nodes = rev_graph_edges(nodes);
243
+ let groups = scc(nodes, &rev_nodes);
244
+
245
+ return groups
246
+ .iter()
247
+ .flat_map(|group| {
248
+ dbg_assert!(!group.is_empty());
249
+ if group.len() == 1 {
250
+ let addr = group[0];
251
+ if addr == ENTRY_NODE_ID {
252
+ let entries = nodes.get(&ENTRY_NODE_ID).unwrap().iter().copied().collect();
253
+ return vec![WasmStructure::Dispatcher(entries)].into_iter();
254
+ }
255
+ let block = WasmStructure::BasicBlock(addr);
256
+ // self-loops
257
+ if nodes.get(&group[0]).unwrap().contains(&group[0]) {
258
+ return vec![WasmStructure::Loop(vec![block])].into_iter();
259
+ }
260
+ else {
261
+ return vec![block].into_iter();
262
+ }
263
+ }
264
+
265
+ let entries_to_group: Vec<u32> = group
266
+ .iter()
267
+ .filter(|addr| {
268
+ // reachable from outside of the group
269
+ rev_nodes.get(addr).map_or(false, |x| {
270
+ x.iter().any(|incoming| !group.contains(incoming))
271
+ })
272
+ })
273
+ .copied()
274
+ .collect();
275
+
276
+ if entries_to_group.len() != 1 {
277
+ //dbg_log!(
278
+ // "Compiling multi-entry loop with {} entries and {} basic blocks",
279
+ // entries_to_group.len(),
280
+ // group.len()
281
+ //);
282
+ }
283
+
284
+ let max_extra_basic_blocks = unsafe { MAX_EXTRA_BASIC_BLOCKS } as usize;
285
+
286
+ if entries_to_group.len() * group.len() > max_extra_basic_blocks {
287
+ let mut subgroup_edges: Graph = Graph::new();
288
+ for elem in group {
289
+ subgroup_edges.insert(
290
+ *elem,
291
+ nodes
292
+ .get(&elem)
293
+ .unwrap()
294
+ .iter()
295
+ .filter(|dest| {
296
+ // XXX: This might remove forward edges to other loop entries
297
+ // Probably not an issue since it can go through the
298
+ // dispatcher
299
+ group.contains(dest) && !entries_to_group.contains(dest)
300
+ })
301
+ .copied()
302
+ .collect(),
303
+ );
304
+ }
305
+
306
+ let mut loop_nodes = loopify(&subgroup_edges);
307
+
308
+ if entries_to_group.len() > 1 {
309
+ loop_nodes.insert(0, WasmStructure::Dispatcher(entries_to_group));
310
+ }
311
+
312
+ return vec![WasmStructure::Loop(loop_nodes)].into_iter();
313
+ }
314
+ else {
315
+ profiler::stat_increment_by(
316
+ profiler::stat::COMPILE_DUPLICATED_BASIC_BLOCK,
317
+ ((entries_to_group.len() - 1) * group.len()) as u64,
318
+ );
319
+
320
+ let nodes: Vec<WasmStructure> = entries_to_group
321
+ .iter()
322
+ .map(|&entry| {
323
+ let mut subgroup_edges: Graph = Graph::new();
324
+ for &elem in group {
325
+ subgroup_edges.insert(
326
+ elem,
327
+ nodes
328
+ .get(&elem)
329
+ .unwrap()
330
+ .iter()
331
+ .copied()
332
+ .filter(|dest| group.contains(dest) && *dest != entry)
333
+ .collect(),
334
+ );
335
+ }
336
+ let loop_nodes = loopify(&subgroup_edges);
337
+ WasmStructure::Loop(loop_nodes)
338
+ })
339
+ .collect();
340
+
341
+ nodes.into_iter()
342
+ }
343
+ })
344
+ .collect();
345
+ }
346
+
347
+ pub fn blockify(blocks: &mut Vec<WasmStructure>, edges: &Graph) {
348
+ let mut cached_branches: Vec<HashSet<u32>> = Vec::new();
349
+ for i in 0..blocks.len() {
350
+ cached_branches.push(blocks[i].branches(edges));
351
+ }
352
+
353
+ let mut i = 0;
354
+ while i < blocks.len() {
355
+ match &mut blocks[i] {
356
+ WasmStructure::BasicBlock(_) | WasmStructure::Dispatcher(_) => {},
357
+ WasmStructure::Loop (
358
+ blocks
359
+ )
360
+ // TODO: Might be faster to do this *after* inserting blocks in this block
361
+ | WasmStructure::Block(blocks) => blockify(blocks, edges),
362
+ }
363
+
364
+ let source = {
365
+ let mut source = None;
366
+ for j in 0..i {
367
+ if blocks[i].head().any(|bb| cached_branches[j].contains(&bb)) {
368
+ source = Some(j);
369
+ break;
370
+ }
371
+ }
372
+ match source {
373
+ Some(s) => s,
374
+ None => {
375
+ i += 1;
376
+ continue;
377
+ },
378
+ }
379
+ };
380
+
381
+ // This is optional: Avoid putting a single basic block into a block
382
+ if source == i - 1 {
383
+ match &blocks[source] {
384
+ &WasmStructure::BasicBlock(_) => {
385
+ i += 1;
386
+ continue;
387
+ },
388
+ _ => {},
389
+ }
390
+ }
391
+
392
+ let replacement = WasmStructure::Block(Vec::new());
393
+ let children: Vec<WasmStructure> =
394
+ blocks.splice(source..i, iter::once(replacement)).collect();
395
+ match &mut blocks[source] {
396
+ WasmStructure::Block(c) => c.extend(children),
397
+ _ => {
398
+ dbg_assert!(false);
399
+ },
400
+ }
401
+ match &blocks[source + 1] {
402
+ WasmStructure::BasicBlock(_) =>
403
+ //dbg_assert!(*b == bbs.next().unwrap())
404
+ {},
405
+ WasmStructure::Dispatcher(_) => {},
406
+ WasmStructure::Loop(_blocks) | WasmStructure::Block(_blocks) => {}, //dbg_assert!(blocks[0].head() == bb),
407
+ }
408
+
409
+ {
410
+ let replacement = HashSet::new();
411
+ let children: Vec<HashSet<u32>> = cached_branches
412
+ .splice(source..i, iter::once(replacement))
413
+ .collect();
414
+ dbg_assert!(cached_branches[source].len() == 0);
415
+ let mut iter = children.into_iter();
416
+ cached_branches[source] = iter.next().unwrap();
417
+ for c in iter {
418
+ cached_branches[source].extend(c);
419
+ }
420
+ }
421
+
422
+ // skip the inserted block and this block
423
+ i = source + 2;
424
+ }
425
+ }