virtual-machine 0.7.2 → 0.7.5

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/README.md CHANGED
@@ -4,7 +4,7 @@ A complete RISC-V 64-bit (RV64GC) virtual machine implementation in Rust, capabl
4
4
 
5
5
  ## Features
6
6
 
7
- - **Core**: Full RV64GC instruction set implementation (IMAFDC + Zicsr + Zifencei).
7
+ - **Core**: RV64GC instruction set implementation (IMAFDC + Zicsr + Zifencei). Integer, atomic and compressed instructions run in a superblock engine with a devirtualized memory fast path; F/D floating-point executes in the interpreter (NaN boxing, all rounding modes for conversions, fcsr flags). Misaligned scalar accesses to RAM are handled in hardware style (no trap).
8
8
  - **Memory**: Sv39 Virtual Memory Management Unit (MMU) with TLB.
9
9
  - **Peripherals**:
10
10
  - **UART**: 16550-compatible serial console.
@@ -217,17 +217,17 @@ if (!("encodeInto" in cachedTextEncoder)) {
217
217
  };
218
218
  }
219
219
  var WASM_VECTOR_LEN = 0;
220
- function wasm_bindgen__convert__closures_____invoke__h4e3f98878f091896(arg0, arg1) {
221
- wasm.wasm_bindgen__convert__closures_____invoke__h4e3f98878f091896(arg0, arg1);
220
+ function wasm_bindgen__convert__closures_____invoke__h10fd13f77519f00f(arg0, arg1, arg2) {
221
+ wasm.wasm_bindgen__convert__closures_____invoke__h10fd13f77519f00f(arg0, arg1, arg2);
222
222
  }
223
- function wasm_bindgen__convert__closures_____invoke__h260170fb96639bcf(arg0, arg1, arg2) {
224
- wasm.wasm_bindgen__convert__closures_____invoke__h260170fb96639bcf(arg0, arg1, arg2);
223
+ function wasm_bindgen__convert__closures_____invoke__h3c19a701e2fb4946(arg0, arg1, arg2) {
224
+ wasm.wasm_bindgen__convert__closures_____invoke__h3c19a701e2fb4946(arg0, arg1, arg2);
225
225
  }
226
- function wasm_bindgen__convert__closures_____invoke__h658bde57dcf0e58b(arg0, arg1) {
227
- wasm.wasm_bindgen__convert__closures_____invoke__h658bde57dcf0e58b(arg0, arg1);
226
+ function wasm_bindgen__convert__closures_____invoke__h6ce8d92453d66e1b(arg0, arg1) {
227
+ wasm.wasm_bindgen__convert__closures_____invoke__h6ce8d92453d66e1b(arg0, arg1);
228
228
  }
229
- function wasm_bindgen__convert__closures_____invoke__h5006ec25729b138d(arg0, arg1, arg2) {
230
- wasm.wasm_bindgen__convert__closures_____invoke__h5006ec25729b138d(arg0, arg1, arg2);
229
+ function wasm_bindgen__convert__closures_____invoke__h1f45221b43ca80d0(arg0, arg1) {
230
+ wasm.wasm_bindgen__convert__closures_____invoke__h1f45221b43ca80d0(arg0, arg1);
231
231
  }
232
232
  var __wbindgen_enum_WorkerType = ["classic", "module"];
233
233
  var WasmVmFinalization = typeof FinalizationRegistry === "undefined" ? { register: () => {
@@ -647,6 +647,16 @@ var WasmVm = class _WasmVm {
647
647
  const ret = wasm.wasmvm_get_gpu_dirty_rect(this.__wbg_ptr);
648
648
  return ret;
649
649
  }
650
+ /**
651
+ * Reset hart 0 to bare machine mode at the entry point.
652
+ *
653
+ * Benchmark workloads (see `bench_workload`) are M-mode programs; this
654
+ * undoes the S-mode boot setup that `new_with_harts` applies so they
655
+ * run exactly like under the native bench runner.
656
+ */
657
+ reset_machine_mode() {
658
+ wasm.wasmvm_reset_machine_mode(this.__wbg_ptr);
659
+ }
650
660
  /**
651
661
  * Check if cancellation has been requested.
652
662
  * @returns {boolean}
@@ -684,10 +694,14 @@ var WasmVm = class _WasmVm {
684
694
  * Get a direct zero-copy view into the framebuffer in SharedArrayBuffer.
685
695
  *
686
696
  * This eliminates all memory copies by creating a Uint8Array view directly
687
- * into the SharedArrayBuffer at the framebuffer offset. The browser can
688
- * pass this directly to WebGPU's writeTexture for zero-copy rendering.
697
+ * into guest memory at the framebuffer offset. The browser can pass this
698
+ * directly to WebGPU's writeTexture for zero-copy rendering.
689
699
  *
690
- * Returns None if SharedArrayBuffer is not available (single-threaded mode).
700
+ * Works in both memory modes:
701
+ * - SMP (SharedArrayBuffer): stable view into the SAB.
702
+ * - Single-hart (linear memory): view into WASM linear memory. This view
703
+ * is invalidated whenever WASM memory grows, so consume it immediately
704
+ * and call this again each frame (do not cache it JS-side).
691
705
  * @returns {Uint8Array | undefined}
692
706
  */
693
707
  get_framebuffer_view() {
@@ -845,7 +859,11 @@ var WasmVm = class _WasmVm {
845
859
  }
846
860
  /**
847
861
  * Push an input byte to the UART.
848
- * In SMP mode, this also writes to the shared input buffer so workers can receive it.
862
+ *
863
+ * In SMP mode there is a single shared input ring consumed by whichever
864
+ * hart runs the shell (the bus routes RBR/LSR reads of every hart,
865
+ * including hart 0, to the ring). Pushing to the local FIFO as well
866
+ * would duplicate the stream and leave stale bytes behind.
849
867
  * @param {number} byte
850
868
  */
851
869
  input(byte) {
@@ -860,10 +878,13 @@ var WasmVm = class _WasmVm {
860
878
  return ret !== 0;
861
879
  }
862
880
  /**
863
- * Execute up to N instructions in a batch.
864
- * Returns the number of instructions actually executed.
865
- * This is more efficient than calling step() N times due to reduced
866
- * JS-WASM boundary crossings.
881
+ * Execute up to N instructions by looping `step()`.
882
+ *
883
+ * DEPRECATED for hot paths: prefer `run_batch`, which hoists device
884
+ * polling and CLINT sync out of the instruction loop and returns early
885
+ * on WFI. `step_n` keeps the historical contract that a return value
886
+ * less than `count` means the VM halted (it never stops early on WFI),
887
+ * which existing consumers rely on for halt detection.
867
888
  * @param {number} count
868
889
  * @returns {number}
869
890
  */
@@ -871,6 +892,17 @@ var WasmVm = class _WasmVm {
871
892
  const ret = wasm.wasmvm_step_n(this.__wbg_ptr, count);
872
893
  return ret >>> 0;
873
894
  }
895
+ /**
896
+ * Total retired guest instructions on hart 0.
897
+ *
898
+ * Unlike step counts, this reflects real instructions (superblock
899
+ * execution retires many instructions per step). Use for MIPS metrics.
900
+ * @returns {number}
901
+ */
902
+ instret() {
903
+ const ret = wasm.wasmvm_instret(this.__wbg_ptr);
904
+ return ret;
905
+ }
874
906
  /**
875
907
  * Get the entry PC address for workers.
876
908
  * This is the address where secondary harts should start executing.
@@ -940,6 +972,25 @@ var WasmVm = class _WasmVm {
940
972
  const ret = wasm.wasmvm_num_harts(this.__wbg_ptr);
941
973
  return ret >>> 0;
942
974
  }
975
+ /**
976
+ * Execute up to N instructions in a batch with device polling, CLINT
977
+ * sync, and RTC updates hoisted to chunk boundaries.
978
+ *
979
+ * This is the fast path for hart 0: the inner loop is a tight
980
+ * `cpu.step()` with no per-instruction bookkeeping. Interrupt latency
981
+ * is bounded by IRQ_SYNC_INTERVAL (shared-CLINT sync) and the CPU's own
982
+ * internal 256-instruction interrupt poll.
983
+ *
984
+ * Returns the number of dispatcher steps executed (superblocks count as
985
+ * one step; use `instret()` for true instruction counts). Returns early
986
+ * on halt or WFI so the JS caller can pace execution.
987
+ * @param {number} max_steps
988
+ * @returns {number}
989
+ */
990
+ run_batch(max_steps) {
991
+ const ret = wasm.wasmvm_run_batch(this.__wbg_ptr, max_steps);
992
+ return ret >>> 0;
993
+ }
943
994
  };
944
995
  if (Symbol.dispose) WasmVm.prototype[Symbol.dispose] = WasmVm.prototype.free;
945
996
  var WorkerState = class {
@@ -1055,6 +1106,17 @@ var WorkerStepResult = Object.freeze({
1055
1106
  Wfi: 4,
1056
1107
  "4": "Wfi"
1057
1108
  });
1109
+ function bench_workload(name) {
1110
+ const ptr0 = passStringToWasm0(name, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
1111
+ const len0 = WASM_VECTOR_LEN;
1112
+ const ret = wasm.bench_workload(ptr0, len0);
1113
+ if (ret[3]) {
1114
+ throw takeFromExternrefTable0(ret[2]);
1115
+ }
1116
+ var v2 = getArrayU8FromWasm0(ret[0], ret[1]).slice();
1117
+ wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);
1118
+ return v2;
1119
+ }
1058
1120
  function worker_check_interrupts(hart_id, shared_mem) {
1059
1121
  const ret = wasm.worker_check_interrupts(hart_id, shared_mem);
1060
1122
  return BigInt.asUintN(64, ret);
@@ -1358,10 +1420,6 @@ function __wbg_get_imports() {
1358
1420
  return ret;
1359
1421
  }, arguments);
1360
1422
  };
1361
- imports.wbg.__wbg_new_with_shared_array_buffer_f801846979192910 = function(arg0, arg1, arg2) {
1362
- const ret = new DataView(arg0, arg1 >>> 0, arg2 >>> 0);
1363
- return ret;
1364
- };
1365
1423
  imports.wbg.__wbg_notify_65c8811cd7c0cdea = function() {
1366
1424
  return handleError(function(arg0, arg1, arg2) {
1367
1425
  const ret = Atomics.notify(arg0, arg1 >>> 0, arg2 >>> 0);
@@ -1530,24 +1588,28 @@ function __wbg_get_imports() {
1530
1588
  const ret = getStringFromWasm0(arg0, arg1);
1531
1589
  return ret;
1532
1590
  };
1533
- imports.wbg.__wbindgen_cast_808b97cce14173bb = function(arg0, arg1) {
1534
- const ret = makeMutClosure(arg0, arg1, wasm.wasm_bindgen__closure__destroy__h16ea2e7332e3f0d8, wasm_bindgen__convert__closures_____invoke__h658bde57dcf0e58b);
1591
+ imports.wbg.__wbindgen_cast_37ec172324e9c759 = function(arg0, arg1) {
1592
+ const ret = makeMutClosure(arg0, arg1, wasm.wasm_bindgen__closure__destroy__h1e8cf243a981f4cd, wasm_bindgen__convert__closures_____invoke__h1f45221b43ca80d0);
1535
1593
  return ret;
1536
1594
  };
1537
- imports.wbg.__wbindgen_cast_97885f52609c7a81 = function(arg0, arg1) {
1538
- const ret = makeMutClosure(arg0, arg1, wasm.wasm_bindgen__closure__destroy__h16ea2e7332e3f0d8, wasm_bindgen__convert__closures_____invoke__h5006ec25729b138d);
1595
+ imports.wbg.__wbindgen_cast_5d29676ef6c3e85f = function(arg0, arg1) {
1596
+ const ret = makeMutClosure(arg0, arg1, wasm.wasm_bindgen__closure__destroy__h1e8cf243a981f4cd, wasm_bindgen__convert__closures_____invoke__h3c19a701e2fb4946);
1539
1597
  return ret;
1540
1598
  };
1541
- imports.wbg.__wbindgen_cast_9d58885f229d7092 = function(arg0, arg1) {
1542
- const ret = makeMutClosure(arg0, arg1, wasm.wasm_bindgen__closure__destroy__h612f8e24953b61d5, wasm_bindgen__convert__closures_____invoke__h260170fb96639bcf);
1599
+ imports.wbg.__wbindgen_cast_5f9a13552260be22 = function(arg0, arg1) {
1600
+ const ret = makeMutClosure(arg0, arg1, wasm.wasm_bindgen__closure__destroy__h98fb6f0c0578da12, wasm_bindgen__convert__closures_____invoke__h10fd13f77519f00f);
1543
1601
  return ret;
1544
1602
  };
1545
- imports.wbg.__wbindgen_cast_d6cd19b81560fd6e = function(arg0) {
1546
- const ret = arg0;
1603
+ imports.wbg.__wbindgen_cast_c6620a1285ea2988 = function(arg0, arg1) {
1604
+ const ret = makeClosure(arg0, arg1, wasm.wasm_bindgen__closure__destroy__h1e8cf243a981f4cd, wasm_bindgen__convert__closures_____invoke__h6ce8d92453d66e1b);
1547
1605
  return ret;
1548
1606
  };
1549
- imports.wbg.__wbindgen_cast_e7df37cfbf20cf37 = function(arg0, arg1) {
1550
- const ret = makeClosure(arg0, arg1, wasm.wasm_bindgen__closure__destroy__h16ea2e7332e3f0d8, wasm_bindgen__convert__closures_____invoke__h4e3f98878f091896);
1607
+ imports.wbg.__wbindgen_cast_cb9088102bce6b30 = function(arg0, arg1) {
1608
+ const ret = getArrayU8FromWasm0(arg0, arg1);
1609
+ return ret;
1610
+ };
1611
+ imports.wbg.__wbindgen_cast_d6cd19b81560fd6e = function(arg0) {
1612
+ const ret = arg0;
1551
1613
  return ret;
1552
1614
  };
1553
1615
  imports.wbg.__wbindgen_init_externref_table = function() {
@@ -1609,6 +1671,7 @@ export {
1609
1671
  WasmVm,
1610
1672
  WorkerState,
1611
1673
  WorkerStepResult,
1674
+ bench_workload,
1612
1675
  worker_check_interrupts,
1613
1676
  worker_entry,
1614
1677
  initSync,