@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,6 @@
1
+ use crate::cpu::cpu::translate_address_system_read;
2
+
3
+ #[no_mangle]
4
+ pub unsafe fn translate_address_system_read_js(addr: i32) -> u32 {
5
+ translate_address_system_read(addr).unwrap()
6
+ }
@@ -0,0 +1,46 @@
1
+ pub fn write_leb_i32(buf: &mut Vec<u8>, v: i32) { write_leb_i64(buf, v as i64); }
2
+
3
+ pub fn write_leb_i64(buf: &mut Vec<u8>, mut v: i64) {
4
+ // https://en.wikipedia.org/wiki/LEB128#Encode_signed_integer
5
+ loop {
6
+ let mut byte = v as u8 & 0b0111_1111;
7
+ v >>= 7;
8
+ let sign = byte & (1 << 6);
9
+ let done = v == 0 && sign == 0 || v == -1 && sign != 0;
10
+ if !done {
11
+ byte |= 0b1000_0000;
12
+ }
13
+ buf.push(byte);
14
+ if done {
15
+ break;
16
+ }
17
+ }
18
+ }
19
+
20
+ pub fn write_leb_u32(buf: &mut Vec<u8>, mut v: u32) {
21
+ loop {
22
+ let mut byte = v as u8 & 0b0111_1111;
23
+ v >>= 7;
24
+ if v != 0 {
25
+ byte |= 0b1000_0000;
26
+ }
27
+ buf.push(byte);
28
+ if v == 0 {
29
+ break;
30
+ }
31
+ }
32
+ }
33
+
34
+ pub fn write_fixed_leb16_at_idx(vec: &mut Vec<u8>, idx: usize, x: u16) {
35
+ dbg_assert!(x < (1 << 14)); // we have 14 bits of available space in 2 bytes for leb
36
+ vec[idx] = ((x & 0b1111111) | 0b10000000) as u8;
37
+ vec[idx + 1] = (x >> 7) as u8;
38
+ }
39
+
40
+ pub fn write_fixed_leb32_at_idx(vec: &mut Vec<u8>, idx: usize, x: u32) {
41
+ dbg_assert!(x < (1 << 28)); // we have 28 bits of available space in 4 bytes for leb
42
+ vec[idx] = (x & 0b1111111) as u8 | 0b10000000;
43
+ vec[idx + 1] = (x >> 7 & 0b1111111) as u8 | 0b10000000;
44
+ vec[idx + 2] = (x >> 14 & 0b1111111) as u8 | 0b10000000;
45
+ vec[idx + 3] = (x >> 21 & 0b1111111) as u8;
46
+ }
@@ -0,0 +1,29 @@
1
+ #[macro_use]
2
+ mod dbg;
3
+
4
+ #[macro_use]
5
+ mod paging;
6
+
7
+ pub mod cpu;
8
+
9
+ pub mod js_api;
10
+ pub mod profiler;
11
+
12
+ mod analysis;
13
+ mod codegen;
14
+ mod config;
15
+ mod control_flow;
16
+ mod cpu_context;
17
+ mod gen;
18
+ mod jit;
19
+ mod jit_instructions;
20
+ mod leb;
21
+ mod modrm;
22
+ mod opstats;
23
+ mod page;
24
+ mod prefix;
25
+ mod regs;
26
+ mod softfloat;
27
+ mod state_flags;
28
+ mod wasmgen;
29
+ mod zstd;
@@ -0,0 +1,330 @@
1
+ use crate::codegen;
2
+ use crate::cpu::global_pointers;
3
+ use crate::cpu_context::CpuContext;
4
+ use crate::jit::JitContext;
5
+ use crate::prefix::{PREFIX_MASK_SEGMENT, SEG_PREFIX_ZERO};
6
+ use crate::profiler;
7
+ use crate::regs::{BP, BX, DI, SI};
8
+ use crate::regs::{CS, DS, ES, FS, GS, SS};
9
+ use crate::regs::{EAX, EBP, EBX, ECX, EDI, EDX, ESI, ESP};
10
+
11
+ pub struct ModrmByte {
12
+ segment: u32,
13
+ first_reg: Option<u32>,
14
+ second_reg: Option<u32>,
15
+ shift: u8,
16
+ immediate: i32,
17
+ is_16: bool,
18
+ }
19
+ impl ModrmByte {
20
+ pub fn is_nop(&self, reg: u32) -> bool {
21
+ self.first_reg == Some(reg)
22
+ && self.second_reg.is_none()
23
+ && self.shift == 0
24
+ && self.immediate == 0
25
+ && !self.is_16
26
+ }
27
+ }
28
+
29
+ pub fn decode(ctx: &mut CpuContext, modrm_byte: u8) -> ModrmByte {
30
+ if ctx.asize_32() {
31
+ decode32(ctx, modrm_byte)
32
+ }
33
+ else {
34
+ decode16(ctx, modrm_byte)
35
+ }
36
+ }
37
+
38
+ fn decode16(ctx: &mut CpuContext, modrm_byte: u8) -> ModrmByte {
39
+ fn mk16(
40
+ segment: u32,
41
+ first_reg: Option<u32>,
42
+ second_reg: Option<u32>,
43
+ immediate: i32,
44
+ ) -> ModrmByte {
45
+ ModrmByte {
46
+ segment,
47
+ first_reg,
48
+ second_reg,
49
+ shift: 0,
50
+ immediate,
51
+ is_16: true,
52
+ }
53
+ }
54
+
55
+ match modrm_byte & !0o070 {
56
+ 0o000 => mk16(DS, Some(BX), Some(SI), 0),
57
+ 0o001 => mk16(DS, Some(BX), Some(DI), 0),
58
+ 0o002 => mk16(SS, Some(BP), Some(SI), 0),
59
+ 0o003 => mk16(SS, Some(BP), Some(DI), 0),
60
+ 0o004 => mk16(DS, Some(SI), None, 0),
61
+ 0o005 => mk16(DS, Some(DI), None, 0),
62
+ 0o006 => mk16(DS, None, None, ctx.read_imm16() as i32),
63
+ 0o007 => mk16(DS, Some(BX), None, 0),
64
+
65
+ 0o100 => mk16(DS, Some(BX), Some(SI), ctx.read_imm8s() as i32),
66
+ 0o101 => mk16(DS, Some(BX), Some(DI), ctx.read_imm8s() as i32),
67
+ 0o102 => mk16(SS, Some(BP), Some(SI), ctx.read_imm8s() as i32),
68
+ 0o103 => mk16(SS, Some(BP), Some(DI), ctx.read_imm8s() as i32),
69
+ 0o104 => mk16(DS, Some(SI), None, ctx.read_imm8s() as i32),
70
+ 0o105 => mk16(DS, Some(DI), None, ctx.read_imm8s() as i32),
71
+ 0o106 => mk16(SS, Some(BP), None, ctx.read_imm8s() as i32),
72
+ 0o107 => mk16(DS, Some(BX), None, ctx.read_imm8s() as i32),
73
+
74
+ 0o200 => mk16(DS, Some(BX), Some(SI), ctx.read_imm16() as i32),
75
+ 0o201 => mk16(DS, Some(BX), Some(DI), ctx.read_imm16() as i32),
76
+ 0o202 => mk16(SS, Some(BP), Some(SI), ctx.read_imm16() as i32),
77
+ 0o203 => mk16(SS, Some(BP), Some(DI), ctx.read_imm16() as i32),
78
+ 0o204 => mk16(DS, Some(SI), None, ctx.read_imm16() as i32),
79
+ 0o205 => mk16(DS, Some(DI), None, ctx.read_imm16() as i32),
80
+ 0o206 => mk16(SS, Some(BP), None, ctx.read_imm16() as i32),
81
+ 0o207 => mk16(DS, Some(BX), None, ctx.read_imm16() as i32),
82
+
83
+ _ => panic!("modrm byte >= 0xC0"),
84
+ }
85
+ }
86
+
87
+ fn decode32(ctx: &mut CpuContext, modrm_byte: u8) -> ModrmByte {
88
+ fn mk32(segment: u32, first_reg: Option<u32>, immediate: i32) -> ModrmByte {
89
+ ModrmByte {
90
+ segment,
91
+ first_reg,
92
+ second_reg: None,
93
+ shift: 0,
94
+ immediate,
95
+ is_16: false,
96
+ }
97
+ }
98
+
99
+ match modrm_byte & !0o070 {
100
+ 0o000 => mk32(DS, Some(EAX), 0),
101
+ 0o001 => mk32(DS, Some(ECX), 0),
102
+ 0o002 => mk32(DS, Some(EDX), 0),
103
+ 0o003 => mk32(DS, Some(EBX), 0),
104
+ 0o004 => decode_sib(ctx, Imm32::None),
105
+ 0o005 => mk32(DS, None, ctx.read_imm32() as i32),
106
+ 0o006 => mk32(DS, Some(ESI), 0),
107
+ 0o007 => mk32(DS, Some(EDI), 0),
108
+
109
+ 0o100 => mk32(DS, Some(EAX), ctx.read_imm8s() as i32),
110
+ 0o101 => mk32(DS, Some(ECX), ctx.read_imm8s() as i32),
111
+ 0o102 => mk32(DS, Some(EDX), ctx.read_imm8s() as i32),
112
+ 0o103 => mk32(DS, Some(EBX), ctx.read_imm8s() as i32),
113
+ 0o104 => decode_sib(ctx, Imm32::Imm8),
114
+ 0o105 => mk32(SS, Some(EBP), ctx.read_imm8s() as i32),
115
+ 0o106 => mk32(DS, Some(ESI), ctx.read_imm8s() as i32),
116
+ 0o107 => mk32(DS, Some(EDI), ctx.read_imm8s() as i32),
117
+
118
+ 0o200 => mk32(DS, Some(EAX), ctx.read_imm32() as i32),
119
+ 0o201 => mk32(DS, Some(ECX), ctx.read_imm32() as i32),
120
+ 0o202 => mk32(DS, Some(EDX), ctx.read_imm32() as i32),
121
+ 0o203 => mk32(DS, Some(EBX), ctx.read_imm32() as i32),
122
+ 0o204 => decode_sib(ctx, Imm32::Imm32),
123
+ 0o205 => mk32(SS, Some(EBP), ctx.read_imm32() as i32),
124
+ 0o206 => mk32(DS, Some(ESI), ctx.read_imm32() as i32),
125
+ 0o207 => mk32(DS, Some(EDI), ctx.read_imm32() as i32),
126
+
127
+ _ => panic!("modrm byte >= 0xC0"),
128
+ }
129
+ }
130
+
131
+ fn decode_sib(ctx: &mut CpuContext, immediate: Imm32) -> ModrmByte {
132
+ let sib_byte = ctx.read_imm8();
133
+ let r = sib_byte & 7;
134
+ let m = sib_byte >> 3 & 7;
135
+ let shift = sib_byte >> 6 & 3;
136
+
137
+ let second_reg = if m == 4 { None } else { Some(m as u32) };
138
+
139
+ let segment;
140
+ let reg;
141
+
142
+ if r == 4 {
143
+ segment = SS;
144
+ reg = ESP;
145
+ }
146
+ else if r == 5 {
147
+ if immediate == Imm32::None {
148
+ return ModrmByte {
149
+ segment: DS,
150
+ first_reg: None,
151
+ second_reg,
152
+ shift,
153
+ immediate: ctx.read_imm32() as i32,
154
+ is_16: false,
155
+ };
156
+ }
157
+ else {
158
+ segment = SS;
159
+ reg = EBP;
160
+ }
161
+ }
162
+ else {
163
+ segment = DS;
164
+ reg = r as u32;
165
+ }
166
+
167
+ let immediate = match immediate {
168
+ Imm32::None => 0,
169
+ Imm32::Imm8 => ctx.read_imm8s() as i32,
170
+ Imm32::Imm32 => ctx.read_imm32() as i32,
171
+ };
172
+
173
+ ModrmByte {
174
+ segment,
175
+ first_reg: Some(reg),
176
+ second_reg,
177
+ shift,
178
+ immediate,
179
+ is_16: false,
180
+ }
181
+ }
182
+
183
+ pub fn gen(ctx: &mut JitContext, modrm_byte: ModrmByte, esp_offset: i32) {
184
+ codegen::gen_profiler_stat_increment(
185
+ ctx.builder,
186
+ match modrm_byte {
187
+ ModrmByte {
188
+ first_reg: None,
189
+ second_reg: None,
190
+ ..
191
+ } => profiler::stat::MODRM_SIMPLE_CONST_OFFSET,
192
+ ModrmByte {
193
+ first_reg: Some(_),
194
+ second_reg: None,
195
+ ..
196
+ }
197
+ | ModrmByte {
198
+ first_reg: None,
199
+ second_reg: Some(_),
200
+ shift: 0,
201
+ ..
202
+ } => {
203
+ if modrm_byte.immediate == 0 {
204
+ profiler::stat::MODRM_SIMPLE_REG
205
+ }
206
+ else {
207
+ profiler::stat::MODRM_SIMPLE_REG_WITH_OFFSET
208
+ }
209
+ },
210
+ _ => profiler::stat::MODRM_COMPLEX,
211
+ },
212
+ );
213
+
214
+ let mut have_something_on_stack = false;
215
+
216
+ if let Some(reg) = modrm_byte.first_reg {
217
+ codegen::gen_get_reg32(ctx, reg);
218
+ if reg == ESP && esp_offset != 0 {
219
+ ctx.builder.const_i32(esp_offset);
220
+ ctx.builder.add_i32();
221
+ }
222
+ have_something_on_stack = true;
223
+ }
224
+
225
+ if let Some(reg) = modrm_byte.second_reg {
226
+ codegen::gen_get_reg32(ctx, reg);
227
+ dbg_assert!(reg != ESP); // second reg cannot be esp, no need to handle esp_offset
228
+ if modrm_byte.shift != 0 {
229
+ ctx.builder.const_i32(modrm_byte.shift.into());
230
+ ctx.builder.shl_i32();
231
+ }
232
+ if have_something_on_stack {
233
+ ctx.builder.add_i32();
234
+ }
235
+ have_something_on_stack = true;
236
+ }
237
+
238
+ if modrm_byte.immediate != 0 || !have_something_on_stack {
239
+ ctx.builder.const_i32(modrm_byte.immediate);
240
+ if have_something_on_stack {
241
+ ctx.builder.add_i32();
242
+ }
243
+ }
244
+
245
+ if modrm_byte.is_16 {
246
+ ctx.builder.const_i32(0xFFFF);
247
+ ctx.builder.and_i32();
248
+ }
249
+ jit_add_seg_offset(ctx, modrm_byte.segment);
250
+ }
251
+
252
+ pub fn get_as_reg_index_if_possible(ctx: &mut JitContext, modrm_byte: &ModrmByte) -> Option<u32> {
253
+ let prefix = ctx.cpu.prefixes & PREFIX_MASK_SEGMENT;
254
+ let seg = if prefix != 0 { (prefix - 1) as u32 } else { modrm_byte.segment };
255
+ if can_optimize_get_seg(ctx, seg)
256
+ && modrm_byte.second_reg.is_none()
257
+ && modrm_byte.immediate == 0
258
+ && !modrm_byte.is_16
259
+ && modrm_byte.shift == 0
260
+ {
261
+ modrm_byte.first_reg
262
+ }
263
+ else {
264
+ None
265
+ }
266
+ }
267
+
268
+ pub fn skip(ctx: &mut CpuContext, modrm_byte: u8) { let _ = decode(ctx, modrm_byte); }
269
+
270
+ #[derive(PartialEq)]
271
+ enum Imm32 {
272
+ None,
273
+ Imm8,
274
+ Imm32,
275
+ }
276
+
277
+ fn can_optimize_get_seg(ctx: &mut JitContext, segment: u32) -> bool {
278
+ (segment == DS || segment == SS || segment == CS) && ctx.cpu.has_flat_segmentation()
279
+ }
280
+
281
+ pub fn jit_add_seg_offset(ctx: &mut JitContext, default_segment: u32) {
282
+ let prefix = ctx.cpu.prefixes & PREFIX_MASK_SEGMENT;
283
+
284
+ if prefix == SEG_PREFIX_ZERO {
285
+ return;
286
+ }
287
+
288
+ let seg = if prefix != 0 { (prefix - 1) as u32 } else { default_segment };
289
+ jit_add_seg_offset_no_override(ctx, seg);
290
+ }
291
+
292
+ pub fn jit_add_seg_offset_no_override(ctx: &mut JitContext, seg: u32) {
293
+ if can_optimize_get_seg(ctx, seg) {
294
+ codegen::gen_profiler_stat_increment(ctx.builder, profiler::stat::SEG_OFFSET_OPTIMISED);
295
+ return;
296
+ }
297
+ codegen::gen_profiler_stat_increment(ctx.builder, profiler::stat::SEG_OFFSET_NOT_OPTIMISED);
298
+ codegen::gen_profiler_stat_increment(
299
+ ctx.builder,
300
+ if seg == ES {
301
+ profiler::stat::SEG_OFFSET_NOT_OPTIMISED_ES
302
+ }
303
+ else if seg == FS {
304
+ profiler::stat::SEG_OFFSET_NOT_OPTIMISED_FS
305
+ }
306
+ else if seg == GS {
307
+ profiler::stat::SEG_OFFSET_NOT_OPTIMISED_GS
308
+ }
309
+ else {
310
+ profiler::stat::SEG_OFFSET_NOT_OPTIMISED_NOT_FLAT
311
+ },
312
+ );
313
+
314
+ if seg != CS && seg != SS {
315
+ if cfg!(feature = "profiler") {
316
+ ctx.builder.const_i32(seg as i32);
317
+ ctx.builder.call_fn1("log_segment_null");
318
+ }
319
+
320
+ ctx.builder
321
+ .load_fixed_u8(global_pointers::get_segment_is_null_offset(seg));
322
+ ctx.builder.if_void();
323
+ codegen::gen_trigger_gp(ctx, 0);
324
+ ctx.builder.block_end();
325
+ }
326
+
327
+ ctx.builder
328
+ .load_fixed_i32(global_pointers::get_seg_offset(seg));
329
+ ctx.builder.add_i32();
330
+ }
@@ -0,0 +1,249 @@
1
+ use crate::wasmgen::wasm_builder::WasmBuilder;
2
+
3
+ const SIZE: usize = if cfg!(feature = "profiler") { 8192 } else { 0 };
4
+
5
+ #[allow(non_upper_case_globals)]
6
+ pub static mut opstats_buffer: [u64; SIZE] = [0; SIZE];
7
+ #[allow(non_upper_case_globals)]
8
+ pub static mut opstats_compiled_buffer: [u64; SIZE] = [0; SIZE];
9
+ #[allow(non_upper_case_globals)]
10
+ pub static mut opstats_jit_exit_buffer: [u64; SIZE] = [0; SIZE];
11
+ #[allow(non_upper_case_globals)]
12
+ pub static mut opstats_unguarded_register_buffer: [u64; SIZE] = [0; SIZE];
13
+ #[allow(non_upper_case_globals)]
14
+ pub static mut opstats_wasm_size: [u64; SIZE] = [0; SIZE];
15
+
16
+ pub struct Instruction {
17
+ pub prefixes: Vec<u8>,
18
+ pub opcode: u8,
19
+ pub fixed_g: u8,
20
+ pub is_mem: bool,
21
+ pub is_0f: bool,
22
+ }
23
+
24
+ pub fn decode(mut instruction: u32) -> Instruction {
25
+ let mut is_0f = false;
26
+ let mut prefixes = vec![];
27
+ let mut final_opcode = 0;
28
+
29
+ for _ in 0..4 {
30
+ let opcode = (instruction & 0xFF) as u8;
31
+ instruction >>= 8;
32
+
33
+ // TODO:
34
+ // - If the instruction uses 4 or more prefixes, only the prefixes will be counted
35
+
36
+ if is_0f {
37
+ final_opcode = opcode;
38
+ break;
39
+ }
40
+ else {
41
+ if opcode == 0x0F {
42
+ is_0f = true;
43
+ }
44
+ else if opcode == 0x26
45
+ || opcode == 0x2E
46
+ || opcode == 0x36
47
+ || opcode == 0x3E
48
+ || opcode == 0x64
49
+ || opcode == 0x65
50
+ || opcode == 0x66
51
+ || opcode == 0x67
52
+ || opcode == 0xF0
53
+ || opcode == 0xF2
54
+ || opcode == 0xF3
55
+ {
56
+ prefixes.push(opcode);
57
+ }
58
+ else {
59
+ final_opcode = opcode;
60
+ break;
61
+ }
62
+ }
63
+ }
64
+
65
+ let has_modrm_byte = if is_0f {
66
+ match final_opcode {
67
+ 0x0 | 0x1 | 0x2 | 0x3 | 0x10 | 0x11 | 0x12 | 0x13 | 0x14 | 0x15 | 0x16 | 0x17
68
+ | 0x18 | 0x19 | 0x20 | 0x21 | 0x22 | 0x23 | 0x28 | 0x29 | 0x40 | 0x41 | 0x42 | 0x43
69
+ | 0x44 | 0x45 | 0x46 | 0x47 | 0x48 | 0x49 | 0x50 | 0x51 | 0x52 | 0x53 | 0x54 | 0x55
70
+ | 0x56 | 0x57 | 0x58 | 0x59 | 0x60 | 0x61 | 0x62 | 0x63 | 0x64 | 0x65 | 0x66 | 0x67
71
+ | 0x68 | 0x69 | 0x70 | 0x71 | 0x72 | 0x73 | 0x74 | 0x75 | 0x76 | 0x90 | 0x91 | 0x92
72
+ | 0x93 | 0x94 | 0x95 | 0x96 | 0x97 | 0x98 | 0x99 | 0x1c | 0x1d | 0x1e | 0x1f | 0x2a
73
+ | 0x2b | 0x2c | 0x2d | 0x2e | 0x2f | 0x4a | 0x4b | 0x4c | 0x4d | 0x4e | 0x4f | 0x5a
74
+ | 0x5b | 0x5c | 0x5d | 0x5e | 0x5f | 0x6a | 0x6b | 0x6c | 0x6d | 0x6e | 0x6f | 0x7e
75
+ | 0x7f | 0x9a | 0x9b | 0x9c | 0x9d | 0x9e | 0x9f | 0xa3 | 0xa4 | 0xa5 | 0xab | 0xac
76
+ | 0xad | 0xae | 0xaf | 0xb0 | 0xb1 | 0xb2 | 0xb3 | 0xb4 | 0xb5 | 0xb6 | 0xb7 | 0xb8
77
+ | 0xba | 0xbb | 0xbc | 0xbd | 0xbe | 0xbf | 0xc0 | 0xc1 | 0xc2 | 0xc3 | 0xc4 | 0xc5
78
+ | 0xc6 | 0xc7 | 0xd1 | 0xd2 | 0xd3 | 0xd4 | 0xd5 | 0xd6 | 0xd7 | 0xd8 | 0xd9 | 0xda
79
+ | 0xdb | 0xdc | 0xdd | 0xde | 0xdf | 0xe0 | 0xe1 | 0xe2 | 0xe3 | 0xe4 | 0xe5 | 0xe6
80
+ | 0xe7 | 0xe8 | 0xe9 | 0xea | 0xeb | 0xec | 0xed | 0xee | 0xef | 0xf1 | 0xf2 | 0xf3
81
+ | 0xf4 | 0xf5 | 0xf6 | 0xf7 | 0xf8 | 0xf9 | 0xfa | 0xfb | 0xfc | 0xfd | 0xfe => true,
82
+ _ => false,
83
+ }
84
+ }
85
+ else {
86
+ match final_opcode {
87
+ 0x0 | 0x1 | 0x2 | 0x3 | 0x8 | 0x9 | 0x10 | 0x11 | 0x12 | 0x13 | 0x18 | 0x19 | 0x20
88
+ | 0x21 | 0x22 | 0x23 | 0x28 | 0x29 | 0x30 | 0x31 | 0x32 | 0x33 | 0x38 | 0x39 | 0x62
89
+ | 0x63 | 0x69 | 0x80 | 0x81 | 0x82 | 0x83 | 0x84 | 0x85 | 0x86 | 0x87 | 0x88 | 0x89
90
+ | 0xa | 0xb | 0x1a | 0x1b | 0x2a | 0x2b | 0x3a | 0x3b | 0x6b | 0x8a | 0x8b | 0x8c
91
+ | 0x8d | 0x8e | 0x8f | 0xc0 | 0xc1 | 0xc4 | 0xc5 | 0xc6 | 0xc7 | 0xd0 | 0xd1 | 0xd2
92
+ | 0xd3 | 0xd8 | 0xd9 | 0xda | 0xdb | 0xdc | 0xdd | 0xde | 0xdf | 0xf6 | 0xf7 | 0xfe
93
+ | 0xff => true,
94
+ _ => false,
95
+ }
96
+ };
97
+
98
+ let has_fixed_g = if is_0f {
99
+ final_opcode == 0x71
100
+ || final_opcode == 0x72
101
+ || final_opcode == 0x73
102
+ || final_opcode == 0xAE
103
+ || final_opcode == 0xBA
104
+ || final_opcode == 0xC7
105
+ }
106
+ else {
107
+ final_opcode >= 0x80 && final_opcode < 0x84
108
+ || final_opcode >= 0xC0 && final_opcode < 0xC2
109
+ || final_opcode >= 0xD0 && final_opcode < 0xD4
110
+ || final_opcode >= 0xD8 && final_opcode < 0xE0
111
+ || final_opcode >= 0xF6 && final_opcode < 0xF8
112
+ || final_opcode == 0xFE
113
+ || final_opcode == 0xFF
114
+ };
115
+
116
+ let mut is_mem = false;
117
+ let mut fixed_g = 0;
118
+
119
+ if has_fixed_g {
120
+ dbg_assert!(has_modrm_byte);
121
+ let modrm_byte = (instruction & 0xFF) as u8;
122
+ fixed_g = modrm_byte >> 3 & 7;
123
+ is_mem = modrm_byte < 0xC0
124
+ }
125
+ if has_modrm_byte {
126
+ let modrm_byte = (instruction & 0xFF) as u8;
127
+ is_mem = modrm_byte < 0xC0
128
+ }
129
+
130
+ Instruction {
131
+ prefixes,
132
+ opcode: final_opcode,
133
+ is_mem,
134
+ fixed_g,
135
+ is_0f,
136
+ }
137
+ }
138
+
139
+ pub fn gen_opstats(builder: &mut WasmBuilder, opcode: u32) {
140
+ if !cfg!(feature = "profiler") {
141
+ return;
142
+ }
143
+
144
+ let instruction = decode(opcode);
145
+
146
+ for prefix in instruction.prefixes {
147
+ let index = (prefix as u32) << 4;
148
+ builder.increment_fixed_i64(
149
+ unsafe { &mut opstats_buffer[index as usize] as *mut _ } as u32,
150
+ 1,
151
+ );
152
+ }
153
+
154
+ let index = (instruction.is_0f as u32) << 12
155
+ | (instruction.opcode as u32) << 4
156
+ | (instruction.is_mem as u32) << 3
157
+ | instruction.fixed_g as u32;
158
+
159
+ builder.increment_fixed_i64(
160
+ unsafe { &mut opstats_buffer[index as usize] as *mut _ } as u32,
161
+ 1,
162
+ );
163
+ }
164
+
165
+ pub fn record_opstat_compiled(opcode: u32) {
166
+ if !cfg!(feature = "profiler") {
167
+ return;
168
+ }
169
+
170
+ let instruction = decode(opcode);
171
+
172
+ for prefix in instruction.prefixes {
173
+ let index = (prefix as u32) << 4;
174
+ unsafe { opstats_compiled_buffer[index as usize] += 1 }
175
+ }
176
+
177
+ let index = (instruction.is_0f as u32) << 12
178
+ | (instruction.opcode as u32) << 4
179
+ | (instruction.is_mem as u32) << 3
180
+ | instruction.fixed_g as u32;
181
+
182
+ unsafe { opstats_compiled_buffer[index as usize] += 1 }
183
+ }
184
+
185
+ pub fn record_opstat_jit_exit(opcode: u32) {
186
+ if !cfg!(feature = "profiler") {
187
+ return;
188
+ }
189
+
190
+ let instruction = decode(opcode);
191
+
192
+ for prefix in instruction.prefixes {
193
+ let index = (prefix as u32) << 4;
194
+ unsafe { opstats_jit_exit_buffer[index as usize] += 1 }
195
+ }
196
+
197
+ let index = (instruction.is_0f as u32) << 12
198
+ | (instruction.opcode as u32) << 4
199
+ | (instruction.is_mem as u32) << 3
200
+ | instruction.fixed_g as u32;
201
+
202
+ unsafe { opstats_jit_exit_buffer[index as usize] += 1 }
203
+ }
204
+
205
+ pub fn gen_opstat_unguarded_register(builder: &mut WasmBuilder, opcode: u32) {
206
+ if !cfg!(feature = "profiler") {
207
+ return;
208
+ }
209
+
210
+ let instruction = decode(opcode);
211
+
212
+ for prefix in instruction.prefixes {
213
+ let index = (prefix as u32) << 4;
214
+ builder.increment_fixed_i64(
215
+ unsafe { &mut opstats_unguarded_register_buffer[index as usize] as *mut _ } as u32,
216
+ 1,
217
+ );
218
+ }
219
+
220
+ let index = (instruction.is_0f as u32) << 12
221
+ | (instruction.opcode as u32) << 4
222
+ | (instruction.is_mem as u32) << 3
223
+ | instruction.fixed_g as u32;
224
+
225
+ builder.increment_fixed_i64(
226
+ unsafe { &mut opstats_unguarded_register_buffer[index as usize] as *mut _ } as u32,
227
+ 1,
228
+ );
229
+ }
230
+
231
+ pub fn record_opstat_size_wasm(opcode: u32, size: u64) {
232
+ if !cfg!(feature = "profiler") {
233
+ return;
234
+ }
235
+
236
+ let instruction = decode(opcode);
237
+
238
+ for prefix in instruction.prefixes {
239
+ let index = (prefix as u32) << 4;
240
+ unsafe { opstats_wasm_size[index as usize] += size }
241
+ }
242
+
243
+ let index = (instruction.is_0f as u32) << 12
244
+ | (instruction.opcode as u32) << 4
245
+ | (instruction.is_mem as u32) << 3
246
+ | instruction.fixed_g as u32;
247
+
248
+ unsafe { opstats_wasm_size[index as usize] += size }
249
+ }
@@ -0,0 +1,15 @@
1
+ use std::ops::RangeInclusive;
2
+
3
+ #[derive(Copy, Clone, Eq, Hash, PartialEq)]
4
+ pub struct Page(u32);
5
+ impl Page {
6
+ pub fn page_of(address: u32) -> Page { Page(address >> 12) }
7
+ pub fn to_address(self) -> u32 { self.0 << 12 }
8
+
9
+ pub fn to_u32(self) -> u32 { self.0 }
10
+ pub fn of_u32(page: u32) -> Page { Page(page) }
11
+
12
+ pub fn address_range(self) -> RangeInclusive<u32> {
13
+ self.to_address()..=self.to_address() + 4095
14
+ }
15
+ }
@@ -0,0 +1,25 @@
1
+ pub type OrPageFault<T> = Result<T, ()>;
2
+
3
+ macro_rules! return_on_pagefault {
4
+ ($expr:expr) => {
5
+ match $expr {
6
+ Ok(v) => v,
7
+ Err(()) => return,
8
+ }
9
+ };
10
+ ($expr:expr, $ret:expr) => {
11
+ match $expr {
12
+ Ok(v) => v,
13
+ Err(()) => return $ret,
14
+ }
15
+ };
16
+ }
17
+
18
+ macro_rules! break_on_pagefault {
19
+ ($expr:expr) => {
20
+ match $expr {
21
+ Ok(v) => v,
22
+ Err(()) => break,
23
+ }
24
+ };
25
+ }