@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
package/src/state.ts ADDED
@@ -0,0 +1,359 @@
1
+ declare let DEBUG: boolean
2
+
3
+ import { h } from './lib.js'
4
+ import { dbg_assert, dbg_log } from './log.js'
5
+
6
+ const STATE_VERSION = 6
7
+ const STATE_MAGIC = 0x86768676 | 0
8
+ const STATE_INDEX_MAGIC = 0
9
+ const STATE_INDEX_VERSION = 1
10
+ const STATE_INDEX_TOTAL_LEN = 2
11
+ const STATE_INDEX_INFO_LEN = 3
12
+ const STATE_INFO_BLOCK_START = 16
13
+
14
+ const ZSTD_MAGIC = 0xfd2fb528
15
+
16
+ export class StateLoadError extends Error {
17
+ constructor(msg: string) {
18
+ super(msg)
19
+ }
20
+ }
21
+
22
+ // Minimal interface for the CPU fields state needs
23
+ interface StateCpu {
24
+ get_state(): any[]
25
+
26
+ set_state(state: any[]): void
27
+ wasm_memory: WebAssembly.Memory
28
+ zstd_create_ctx(len: number): number
29
+ zstd_get_src_ptr(ctx: number): number
30
+ zstd_read(ctx: number, len: number): number
31
+ zstd_read_free(ptr: number, len: number): void
32
+ zstd_free_ctx(ctx: number): void
33
+ }
34
+
35
+ const CONSTRUCTOR_TABLE: Record<string, any> = {
36
+ Map: Map,
37
+ Uint8Array: Uint8Array,
38
+ Int8Array: Int8Array,
39
+ Uint16Array: Uint16Array,
40
+ Int16Array: Int16Array,
41
+ Uint32Array: Uint32Array,
42
+ Int32Array: Int32Array,
43
+ Float32Array: Float32Array,
44
+ Float64Array: Float64Array,
45
+ }
46
+
47
+ function save_object(obj: any, saved_buffers: Uint8Array[]): any {
48
+ if (typeof obj !== 'object' || obj === null) {
49
+ dbg_assert(typeof obj !== 'function')
50
+ return obj
51
+ }
52
+
53
+ if (Array.isArray(obj)) {
54
+ return obj.map((x) => save_object(x, saved_buffers))
55
+ }
56
+
57
+ if (obj instanceof Map) {
58
+ return {
59
+ __state_type__: 'Map',
60
+
61
+ args: Array.from(obj.entries()).map(([k, v]: [any, any]) => [
62
+ save_object(k, saved_buffers),
63
+ save_object(v, saved_buffers),
64
+ ]),
65
+ }
66
+ }
67
+
68
+ if (obj.constructor === Object) {
69
+ console.log(obj)
70
+ dbg_assert(obj.constructor !== Object, 'Expected non-object')
71
+ }
72
+
73
+ if (obj.BYTES_PER_ELEMENT) {
74
+ // Uint8Array, etc.
75
+ const buffer = new Uint8Array(
76
+ obj.buffer,
77
+ obj.byteOffset,
78
+ obj.length * obj.BYTES_PER_ELEMENT,
79
+ )
80
+
81
+ const constructor = obj.constructor.name.replace('bound ', '')
82
+
83
+ dbg_assert(CONSTRUCTOR_TABLE[constructor])
84
+
85
+ return {
86
+ __state_type__: constructor,
87
+ buffer_id: saved_buffers.push(buffer) - 1,
88
+ }
89
+ }
90
+
91
+ if (DEBUG && !obj.get_state) {
92
+ console.log('Object without get_state: ', obj)
93
+ }
94
+
95
+ const state = obj.get_state()
96
+
97
+ const result: any[] = []
98
+
99
+ for (let i = 0; i < state.length; i++) {
100
+ const value = state[i]
101
+
102
+ dbg_assert(typeof value !== 'function')
103
+
104
+ result[i] = save_object(value, saved_buffers)
105
+ }
106
+
107
+ return result
108
+ }
109
+
110
+ function restore_buffers(obj: any, buffers: ArrayBuffer[]): any {
111
+ if (typeof obj !== 'object' || obj === null) {
112
+ dbg_assert(typeof obj !== 'function')
113
+ return obj
114
+ }
115
+
116
+ if (Array.isArray(obj)) {
117
+ for (let i = 0; i < obj.length; i++) {
118
+ obj[i] = restore_buffers(obj[i], buffers)
119
+ }
120
+
121
+ return obj
122
+ }
123
+
124
+ const type = obj['__state_type__']
125
+ dbg_assert(type !== undefined)
126
+
127
+ const constructor = CONSTRUCTOR_TABLE[type]
128
+ dbg_assert(constructor, 'Unkown type: ' + type)
129
+
130
+ if (obj['args'] !== undefined) {
131
+ return new constructor(obj['args'])
132
+ }
133
+
134
+ const buffer = buffers[obj['buffer_id']]
135
+ return new constructor(buffer)
136
+ }
137
+
138
+ export function save_state(cpu: StateCpu): ArrayBuffer {
139
+ const saved_buffers: Uint8Array[] = []
140
+ const state = save_object(cpu, saved_buffers)
141
+
142
+ const buffer_infos: { offset: number; length: number }[] = []
143
+ let total_buffer_size = 0
144
+
145
+ for (let i = 0; i < saved_buffers.length; i++) {
146
+ const len = saved_buffers[i].byteLength
147
+
148
+ buffer_infos[i] = {
149
+ offset: total_buffer_size,
150
+ length: len,
151
+ }
152
+
153
+ total_buffer_size += len
154
+
155
+ // align
156
+ total_buffer_size = (total_buffer_size + 3) & ~3
157
+ }
158
+
159
+ const info_object = JSON.stringify({
160
+ buffer_infos: buffer_infos,
161
+ state: state,
162
+ })
163
+ const info_block = new TextEncoder().encode(info_object)
164
+
165
+ let buffer_block_start = STATE_INFO_BLOCK_START + info_block.length
166
+ buffer_block_start = (buffer_block_start + 3) & ~3
167
+ const total_size = buffer_block_start + total_buffer_size
168
+
169
+ const result = new ArrayBuffer(total_size)
170
+
171
+ const header_block = new Int32Array(result, 0, STATE_INFO_BLOCK_START / 4)
172
+ new Uint8Array(result, STATE_INFO_BLOCK_START, info_block.length).set(
173
+ info_block,
174
+ )
175
+ const buffer_block = new Uint8Array(result, buffer_block_start)
176
+
177
+ header_block[STATE_INDEX_MAGIC] = STATE_MAGIC
178
+ header_block[STATE_INDEX_VERSION] = STATE_VERSION
179
+ header_block[STATE_INDEX_TOTAL_LEN] = total_size
180
+ header_block[STATE_INDEX_INFO_LEN] = info_block.length
181
+
182
+ for (let i = 0; i < saved_buffers.length; i++) {
183
+ const buf = saved_buffers[i]
184
+ dbg_assert(buf.constructor === Uint8Array)
185
+ buffer_block.set(buf, buffer_infos[i].offset)
186
+ }
187
+
188
+ dbg_log('State: json size ' + (info_block.byteLength >> 10) + 'k')
189
+ dbg_log(
190
+ 'State: Total buffers size ' + (buffer_block.byteLength >> 10) + 'k',
191
+ )
192
+
193
+ return result
194
+ }
195
+
196
+ export function restore_state(cpu: StateCpu, state: ArrayBuffer): void {
197
+ const state_bytes = new Uint8Array(state)
198
+
199
+ function read_state_header(
200
+ data: Uint8Array,
201
+ check_length: boolean,
202
+ ): number {
203
+ const len = data.length
204
+
205
+ if (len < STATE_INFO_BLOCK_START) {
206
+ throw new StateLoadError('Invalid length: ' + len)
207
+ }
208
+
209
+ const header_block = new Int32Array(data.buffer, data.byteOffset, 4)
210
+
211
+ if (header_block[STATE_INDEX_MAGIC] !== STATE_MAGIC) {
212
+ throw new StateLoadError(
213
+ 'Invalid header: ' + h(header_block[STATE_INDEX_MAGIC] >>> 0),
214
+ )
215
+ }
216
+
217
+ if (header_block[STATE_INDEX_VERSION] !== STATE_VERSION) {
218
+ throw new StateLoadError(
219
+ 'Version mismatch: dump=' +
220
+ header_block[STATE_INDEX_VERSION] +
221
+ ' we=' +
222
+ STATE_VERSION,
223
+ )
224
+ }
225
+
226
+ if (check_length && header_block[STATE_INDEX_TOTAL_LEN] !== len) {
227
+ throw new StateLoadError(
228
+ "Length doesn't match header: " +
229
+ 'real=' +
230
+ len +
231
+ ' header=' +
232
+ header_block[STATE_INDEX_TOTAL_LEN],
233
+ )
234
+ }
235
+
236
+ return header_block[STATE_INDEX_INFO_LEN]
237
+ }
238
+
239
+ function read_info_block(info_block_buffer: Uint8Array) {
240
+ const info_block = new TextDecoder().decode(info_block_buffer)
241
+ return JSON.parse(info_block)
242
+ }
243
+
244
+ if (new Uint32Array(state_bytes.buffer, 0, 1)[0] === ZSTD_MAGIC) {
245
+ const ctx = cpu.zstd_create_ctx(state_bytes.length)
246
+
247
+ new Uint8Array(
248
+ cpu.wasm_memory.buffer,
249
+ cpu.zstd_get_src_ptr(ctx) >>> 0,
250
+ state_bytes.length,
251
+ ).set(state_bytes)
252
+
253
+ let ptr = cpu.zstd_read(ctx, 16)
254
+ const header_block = new Uint8Array(
255
+ cpu.wasm_memory.buffer,
256
+ ptr >>> 0,
257
+ 16,
258
+ )
259
+ const info_block_len = read_state_header(header_block, false)
260
+ cpu.zstd_read_free(ptr, 16)
261
+
262
+ ptr = cpu.zstd_read(ctx, info_block_len)
263
+ const info_block_buffer = new Uint8Array(
264
+ cpu.wasm_memory.buffer,
265
+ ptr >>> 0,
266
+ info_block_len,
267
+ )
268
+ const info_block_obj = read_info_block(info_block_buffer)
269
+ cpu.zstd_read_free(ptr, info_block_len)
270
+
271
+ let state_object = info_block_obj['state']
272
+ const buffer_infos = info_block_obj['buffer_infos']
273
+ const buffers: ArrayBuffer[] = []
274
+
275
+ let position = STATE_INFO_BLOCK_START + info_block_len
276
+
277
+ for (const buffer_info of buffer_infos) {
278
+ const front_padding = ((position + 3) & ~3) - position
279
+ const CHUNK_SIZE = 1 * 1024 * 1024
280
+
281
+ if (buffer_info.length > CHUNK_SIZE) {
282
+ const chunk_ptr = cpu.zstd_read(ctx, front_padding) >>> 0
283
+ cpu.zstd_read_free(chunk_ptr, front_padding)
284
+
285
+ const buffer = new Uint8Array(buffer_info.length)
286
+ buffers.push(buffer.buffer)
287
+
288
+ let have = 0
289
+ while (have < buffer_info.length) {
290
+ const remaining = buffer_info.length - have
291
+ dbg_assert(remaining >= 0)
292
+ const to_read = Math.min(remaining, CHUNK_SIZE)
293
+
294
+ const read_ptr = cpu.zstd_read(ctx, to_read)
295
+ buffer.set(
296
+ new Uint8Array(
297
+ cpu.wasm_memory.buffer,
298
+ read_ptr >>> 0,
299
+ to_read,
300
+ ),
301
+ have,
302
+ )
303
+ cpu.zstd_read_free(read_ptr, to_read)
304
+
305
+ have += to_read
306
+ }
307
+ } else {
308
+ const chunk_ptr = cpu.zstd_read(
309
+ ctx,
310
+ front_padding + buffer_info.length,
311
+ )
312
+ const offset = (chunk_ptr >>> 0) + front_padding
313
+ buffers.push(
314
+ cpu.wasm_memory.buffer.slice(
315
+ offset,
316
+ offset + buffer_info.length,
317
+ ),
318
+ )
319
+ cpu.zstd_read_free(
320
+ chunk_ptr,
321
+ front_padding + buffer_info.length,
322
+ )
323
+ }
324
+
325
+ position += front_padding + buffer_info.length
326
+ }
327
+
328
+ state_object = restore_buffers(state_object, buffers)
329
+ cpu.set_state(state_object)
330
+
331
+ cpu.zstd_free_ctx(ctx)
332
+ } else {
333
+ const info_block_len = read_state_header(state_bytes, true)
334
+
335
+ if (info_block_len < 0 || info_block_len + 12 >= state_bytes.length) {
336
+ throw new StateLoadError(
337
+ 'Invalid info block length: ' + info_block_len,
338
+ )
339
+ }
340
+
341
+ const info_block_buffer = state_bytes.subarray(
342
+ STATE_INFO_BLOCK_START,
343
+ STATE_INFO_BLOCK_START + info_block_len,
344
+ )
345
+ const info_block_obj = read_info_block(info_block_buffer)
346
+ let state_object = info_block_obj['state']
347
+ const buffer_infos = info_block_obj['buffer_infos']
348
+ let buffer_block_start = STATE_INFO_BLOCK_START + info_block_len
349
+ buffer_block_start = (buffer_block_start + 3) & ~3
350
+
351
+ const buffers = buffer_infos.map((buffer_info: any) => {
352
+ const offset = buffer_block_start + buffer_info.offset
353
+ return state_bytes.buffer.slice(offset, offset + buffer_info.length)
354
+ })
355
+
356
+ state_object = restore_buffers(state_object, buffers)
357
+ cpu.set_state(state_object)
358
+ }
359
+ }