Repository navigation
Native backends: hot code reloading by modifying running binary - #31231
Conversation
259b420 to
f03cd3e
Compare
Ports the v2 -hot-fn option (vlib/v2_toberemoved) to v3: stores the target function name in pref.Preferences.hot_fn and accepts -hot-fn <name> in the v3 driver. Wiring to ssa.BuildOptions and the arm64 raw-code extractor follows in later commits.
Ports the v2 hot-fn extract half (vlib/v2_toberemoved) to v3: wires prefs.hot_fn into ssa.BuildOptions, adds arm64.Gen.extract_function (slices macho.text_data between symbols), and writes the raw bytes to -o instead of linking when -hot-fn is set.
Detects @[live] functions during transform, rewrites their calls/references to __live_<mangled> function pointers, injects live_reload_check() into for loop bodies, and generates a V runtime file (globals, init, reload loop) for arm64 builds.
Removes vlib/v/transform/live.v, whose transform_live_fn was never called; the real injection lives in transform_fn_body/transform_expr guarded by live_reload_runtime. Adds an experimental native (arm64) subsection to the hot code reloading docs.
The C backend hot-reload round trip (ORIGINAL->CHANGED->ANOTHER->STOP) passes on Windows (4/5 local runs; the one failure was a background process exit-code race, covered by vtest retry: 4). Stop skipping Windows in testsuite_begin.
Generated __global live_<mangled> is now typed as fn (...) instead of voidptr, with a type alias per signature, so calls through the pointer compile. Generated source and initial builds use -enable-globals. Fixes the unknown-function and global-name errors in the generated runtime.
Adds platform headers for mmap/mprotect/sys_icache_invalidate and fixes the generated reload command so m/bin are unrolled literals while live_vexe/live_opts/live_source_file stay runtime consts.
The Windows round trip is flaky in this environment; revert the default-on Windows enablement and keep FORCE_LIVE_TEST=1 opt-in.
Global live_* pointers and live_reload_check() are generated into the main module, so only main-module for loops and calls are rewritten. Imported modules keep their normal call paths.
99643f4 to
f1e0cdd
Compare
Compiles examples/hot_reload/message.v with -b arm64 on macOS and asserts the generated binary links.
Use os.file_last_mod_unix for mtime checks and per-OS page allocation/protection/flush helpers, so the generated runtime compiles on macOS, Linux and Windows targets.
Move @[live] collection into collect_live_functions() and call it in both serial and parallel transform entry points, and share the collected metadata with forked workers.
Forked transform workers now inherit live_fns, live_methods, live_source_file and live_reload_runtime so call rewriting also happens in parallel-transformed function bodies.
medvednikov
left a comment
There was a problem hiding this comment.
Reviewed the native ARM64 hot-reload implementation for correctness and runtime safety, ignoring CI as requested. I found a source-level build blocker and three issues in the extraction/reload path; details inline. I have not executed the macOS ARM64 reloader on-device.
- Remove stray PY token that breaks driver module build. - Reject functions with relocations in extract_function instead of emitting silently broken machine code; add regression test. - Bound-check executable page writes and rotate pages, keeping old pages alive for active function pointers. - Verify rebuild success and fresh output before swapping pointers; only advance live_mtime on full success to allow retry. - Document self-contained function limitation.
should be fixed |
medvednikov
left a comment
There was a problem hiding this comment.
Follow-up review of f0730ee (excluding CI): thanks, the four findings from my previous review now have corresponding fixes—the stray PY is gone, relocated object code is rejected, executable page rollover is bounded, and rebuild failures are checked before installing output. However, I found a remaining hole in the relocation check, an allocation-failure path, and a documentation example that the new restriction cannot actually reload. Details inline. I have not executed the reloader on macOS ARM64.
…example - extract_function: also decode PC-relative instructions. A call to an already-emitted function is a direct BL with baked-in displacement and no relocation entry, so it passed the reloc check and copied broken. Reject BL/B with targets outside the function and any ADRP/ADR; recursion and intra-function branches still accepted. Adds regression tests for direct-call rejection and recursion. - runtime: treat mmap MAP_FAILED like nil via live_page_failed, guard the initial mapping and retry allocation on reload, and check mprotect results before writes and pointer installs. - docs: use a self-contained native_counter.v example for the native path; label message.v as C shared-library workflow only. Add macos-arm64 extraction tests (accept self-contained, reject print_message) and remove a dead variable.
Move page allocation/protection/flush helpers out of the common generated runtime into a target-OS shim file, keeping the common file free of platform-specific code.
Add MachOObject.write_elf and write_and_link_linux. The writer now emits a readable ELF64 relocatable object for Linux/AArch64, but linking still fails on macOS-specific runtime symbols (___stdoutp, etc.). This is a first step toward PR-3; not yet functional.
medvednikov
left a comment
There was a problem hiding this comment.
Independent exact-head source reviews and a separate audit approve the final lazy live-metadata implementation. Three consecutive plain ./v self rebuilds passed at this commit under normal vself policy, with a verified output-to-next-input executable chain. Review findings are addressed. The maintainer deferred larger correctness and performance suites until the PR batch merges.
|
Follow-up fixes (commit All three findings from your second review are addressed:
Also removed a dead The PR is merged as |
Adds native ARM64 hot reloading on macOS. Calls and function references to
@[live]functionsuse live pointers; loop checks watch every live source file, rebuild changes, and install new code.
Failed rebuilds publish no partial update, and captured function pointers remain callable after
later reloads. The PR adds
examples/hot_reload/native_counter.vand documentation.-hot-fn <name>extracts a self-contained function as raw machine code. Extraction rejectsrelocations and PC-relative references outside the function; calls, literals, or globals needing
address fixups remain unsupported. Linux ARM64 supports ELF object output; executable output is
rejected.
Review fixes:
expression rewriting in a separate helper.
live forks share an immutable snapshot, and recollection creates a fresh snapshot. Keep new
metadata and preference fields last to preserve existing ordinary field offsets.
offsets, section sizes, and propagated file errors, with regressions for each case.
Validation at
a54ff1b284d268a9e0a1b5bca7867045c204d680:passed actual reloads, failed-update retry, captured pointers, methods, multiple source files,
extraction, and run/test dispatch. Three SSA/WASM files and two extraction/ELF files passed.
Formatting and
git diff --checkpassed.including reads by one pool worker and a forced synchronous caller. This does not establish
full parallel-dispatch, simultaneous-overlap, or race-detector coverage.
stages passed independent review, including ARM64 exclusion and valid byte-identical fixed C.
Static review retains larger structs and constructor/fork costs; it establishes no universal
zero-overhead claim.
One matched ordinary self-compilation-to-C comparison against
3e08b99c85a88c98c6d60fdeb547f364fda6edfbcompleted one warmup per role and ten alternatingAB/BA measured pairs. All 22 runs exited zero with the same 562 files, 559,990 physical source
lines, fixture, standard library, recipe, flags, environment, and output path.
Median instructions changed by -0.10366996%; the median paired difference was -91,758,743,
with 2/10 adverse pairs. Independent acceptance covers this fixed ordinary workload only.
Elapsed time and cycles reflect shared host load; no latency gain, universal compiler-efficiency
gain, or enabled-native performance result is established. Raw logs, inventories, compiler hashes,
and output proofs are retained.
Canonical compiler-error, in/out, and full
vlib/v/suites remain pending at this head. Thecorrected isolated Linux runner has not launched because host disk space is below its unchanged
16 GiB capacity guard. No canonical suite is currently active or claimed as passing.
Final integration remains pending. If #31161 lands first, the known driver-help conflict must
preserve
c|fastc|arm64|x64|wasm|eval, backend-name normalization, and-hot-fnhelp, followed byvalidation of the integrated source. A fresh mergeability check is required before merging.
Pre-merge validation at
a54ff1b284d268a9e0a1b5bca7867045c204d680: three consecutive./v selfrebuilds passed, each invoking the preceding output compiler under normal vself policy. The maintainer requested larger suites after this PR batch merges; any earlier pending suite lists above are deferred coverage rather than merge prerequisites.