@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
package/src/rust/leb.rs
ADDED
|
@@ -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
|
+
}
|
package/src/rust/lib.rs
ADDED
|
@@ -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
|
+
}
|
package/src/rust/page.rs
ADDED
|
@@ -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
|
+
}
|