-
Notifications
You must be signed in to change notification settings - Fork 5
feat: allow extending hyperlight-js-runtime with custom native modules#49
feat: allow extending hyperlight-js-runtime with custom native modules #49simongdavies wants to merge 11 commits into
Conversation
d721317 to
3e43831
Compare
7dcc0a9 to
2741c45
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Adds an extension mechanism to hyperlight-js-runtime so downstream crates can register custom native Rust modules and custom globals (and optionally override built-ins) without forking, and wires host-side embedding to support a custom runtime binary via HYPERLIGHT_JS_RUNTIME_PATH.
Changes:
- Introduces a custom native-module registry +
native_modules!macro and acustom_globals!macro, and updatesJsRuntime::new()init sequence to: built-in globals → custom globals → freeze. - Adds host build-time support for embedding a custom runtime binary (
HYPERLIGHT_JS_RUNTIME_PATH) and ajust test-native-modulespipeline to exercise it. - Adds fixtures, docs, and tests covering custom modules/globals, console extensibility, and post-init freezing behavior.
Reviewed changes
Copilot reviewed 19 out of 25 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/hyperlight-js/tests/native_modules.rs | Ignored VM integration tests validating custom modules/globals via embedded custom runtime. |
| src/hyperlight-js/build.rs | Adds HYPERLIGHT_JS_RUNTIME_PATH override for embedding a custom runtime binary. |
| src/hyperlight-js-runtime/tests/native_modules.rs | Unit/E2E tests for registry, macros, globals setup, freeze behavior, and fixture pipeline. |
| src/hyperlight-js-runtime/tests/fixtures/native_math/src/lib.rs | Fixture native module providing add/multiply. |
| src/hyperlight-js-runtime/tests/fixtures/native_math/Cargo.toml | Fixture crate manifest for native-math. |
| src/hyperlight-js-runtime/tests/fixtures/extended_runtime/src/main.rs | Fixture binary using native_modules! and custom_globals! to extend the runtime. |
| src/hyperlight-js-runtime/tests/fixtures/extended_runtime/Cargo.toml | Fixture binary manifest depending on the runtime lib + fixture module. |
| src/hyperlight-js-runtime/tests/fixtures/extended_runtime/Cargo.lock | Lockfile for the standalone fixture build. |
| src/hyperlight-js-runtime/src/modules/mod.rs | Implements custom module registry, lazy init symbol, unified loader, and both extension macros. |
| src/hyperlight-js-runtime/src/main.rs | Provides empty native_modules!{} / custom_globals!{} symbols for the upstream binary. |
| src/hyperlight-js-runtime/src/lib.rs | Exposes runtime as a library and adds 3-step init (setup → custom globals → freeze). |
| src/hyperlight-js-runtime/src/guest/stubs/srand.rs | Adds libc stub for srand. |
| src/hyperlight-js-runtime/src/guest/stubs/mod.rs | Registers the new/relocated libc stub modules. |
| src/hyperlight-js-runtime/src/guest/stubs/localtime.rs | Adds libc stub implementation for localtime_r. |
| src/hyperlight-js-runtime/src/guest/stubs/io.rs | Adds libc stubs for putchar/fflush. |
| src/hyperlight-js-runtime/src/guest/stubs/clock.rs | Adds libc stubs for clock_gettime/gettimeofday using host time. |
| src/hyperlight-js-runtime/src/guest/mod.rs | Moves guest entrypoint/plumbing into the library (cfg(hyperlight)). |
| src/hyperlight-js-runtime/src/globals/print.rs | Makes print writable during custom-globals phase (frozen later). |
| src/hyperlight-js-runtime/src/globals/mod.rs | Adds freeze() stage API and wires in new freeze module. |
| src/hyperlight-js-runtime/src/globals/freeze.rs | New freeze stage: freezes console object and locks down print. |
| src/hyperlight-js-runtime/src/globals/console.rs | Installs console as an extensible object (not module namespace) before freezing. |
| src/hyperlight-js-runtime/Cargo.toml | Adds [lib] target and makes the bin explicitly point to src/main.rs. |
| docs/extending-runtime.md | Adds documentation for extending runtime with custom modules/globals and embedding workflow. |
| Justfile | Adds test-native-modules pipeline and updates clean/test recipes accordingly. |
| Cargo.toml | Excludes the extended runtime fixture from the workspace. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
75c23b9 to
48a251a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 19 out of 25 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
48a251a to
5915fb7
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 19 out of 25 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
5915fb7 to
d04119c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 19 out of 25 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
d04119c to
5f6e309
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 19 out of 25 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
5f6e309 to
ab48a82
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 19 out of 25 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
ab48a82 to
779877f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 19 out of 25 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
de6bddc to
0b79db1
Compare
Resolves hyperlight-dev#48 Add a registration-based system for extending the JS runtime with custom native (Rust-implemented) modules that run inside the Hyperlight guest VM. Key changes: - hyperlight-js-runtime/Cargo.toml: Add [lib] target so the runtime can be used as a library dependency by extender crates. - modules/mod.rs: Add global CUSTOM_MODULES registry with register_native_module() and builtin_module_names(). NativeModuleLoader checks custom registry first, falls back to built-in modules. Panics if custom module name conflicts with a built-in. - native_modules! macro: Generates init_native_modules() (#[no_mangle]) that registers custom modules. Called automatically via spin::Once on first NativeModuleLoader access — no explicit init needed. - guest/mod.rs: Move hyperlight guest entry point (hyperlight_main, guest_dispatch_function, Host impl, stubs) from main/hyperlight.rs into the lib behind cfg(hyperlight). Extender binaries get all guest infrastructure for free by depending on the lib. - hyperlight-js/build.rs: Add HYPERLIGHT_JS_RUNTIME_PATH env var override to embed custom runtime binaries instead of the default. - host.rs: Restore original Host trait only (no FsHost extraction). Testing: - 13 unit/integration tests in hyperlight-js-runtime (loader, registry, macro, override prevention, E2E with native CLI fixture binary) - 3 Hyperlight VM integration tests in hyperlight-js (#[ignore], run via just test-native-modules) - Extended runtime fixture crate with shared native_math module - just test-native-modules recipe for full hyperlight pipeline Docs: - docs/extending-runtime.md with quick start, host-side usage, native testing, API reference, and architecture diagram Signed-off-by: Simon Davies <simongdavies@users.noreply.github.com>
Add custom_globals! macro alongside native_modules! to allow extender
crates to register global JS objects (TextEncoder, TextDecoder,
polyfills, constants) without modifying hyperlight-js-runtime.
- New custom_globals! macro in modules/mod.rs (same #[no_mangle] + extern
- setup_custom_globals() bridge called in JsRuntime::new() after
built-in globals
- Default empty custom_globals! {} in base runtime main.rs
- Test fixture with globalThis.CUSTOM_GLOBAL_TEST = 42
- 6 new tests: unit e2e + full pipeline (standalone, coexist with
builtins, combined with native modules)
- Documentation in docs/extending-runtime.md
Signed-off-by: Simon Davies <simongdavies@users.noreply.github.com>
- Allow overriding built-in modules (io, crypto, console) via native_modules! — custom modules take priority over built-ins. The require module is protected and cannot be overridden. - Make console and print globals writable during init so custom_globals! can extend them (e.g. add console.warn/error). - Freeze console (Object.freeze) and print (non-writable) after custom_globals! runs — handler code cannot tamper with them. - 3-step init in JsRuntime::new: setup → custom_globals → freeze. - New globals/freeze.rs module for post-init lockdown. - Tests: require override rejection, console extension via custom_globals, freeze verification, console.log after freeze. - Updated docs/extending-runtime.md with override rules. Signed-off-by: Simon Davies <simongdavies@users.noreply.github.com>
Signed-off-by: Simon Davies <simongdavies@users.noreply.github.com>
Signed-off-by: Simon Davies <simongdavies@users.noreply.github.com>
- Copy fn pointer out of CUSTOM_MODULES lock before calling module declaration to prevent potential deadlock (spin::Mutex not re-entrant) - Move cargo:rerun-if-env-changed=HYPERLIGHT_JS_RUNTIME_PATH before the match so Cargo tracks the env var even when unset; use canonical path for rerun-if-changed - Lock down globalThis.console binding (non-writable/non-configurable) after Object.freeze to prevent handler code replacing it entirely - Fix test doc comment: built-in overrides work except for require Signed-off-by: Simon Davies <simongdavies@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Simon Davies <simongdavies@users.noreply.github.com>
Previously an empty env var value would panic at canonicalize() with a confusing error. Now we treat empty/whitespace values the same as unset and fall through to build_js_runtime(). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Simon Davies <simongdavies@users.noreply.github.com>
- Fix import ordering in guest/mod.rs (cargo fmt) - Fix line length in clock.rs (cargo fmt) - Add missing ImportAttributes (None) arg to resolve/load calls in tests to match the updated rquickjs trait signatures from the rebase Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Simon Davies <simongdavies@users.noreply.github.com>
0b79db1 to
6b078d2
Compare
The lockfile was stale after rebasing onto main (hyperlight-core 0.15.0, rquickjs 0.12.0, etc). CI failed with --locked because the lock needed updating. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Simon Davies <simongdavies@users.noreply.github.com>
The native_math and extended_runtime fixtures depended on rquickjs 0.11, but hyperlight-js-runtime uses 0.12 after the rebase. This caused a 'multiple different versions of crate rquickjs_core' compile error when linking the extended_runtime binary. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Simon Davies <simongdavies@users.noreply.github.com>
Uh oh!
There was an error while loading. Please reload this page.
Resolves #48
Overview
Adds an extension system that lets downstream crates add custom native modules, custom globals, and override built-in modules — without forking the runtime.
Architecture
Three macros, one init sequence:
native_modules!— Custom native modulesRegister Rust-implemented modules that guest JS can
import:io,crypto,consolecan be overriddenrequirecannot be overridden (panics — it's core infrastructure)#[no_mangle]+extern "Rust"linkagecustom_globals!— Custom global objectsRegister global objects (constructors, polyfills, constants) without import:
console(addwarn,error,info,debug)#[rquickjs::class]) and JS polyfills (ctx.eval()) supportedGlobals freeze
After
custom_globals!runs, built-in globals are locked down:console→Object.freeze()(no new properties, no modifications)print→ non-writable, non-configurablerequire→ already non-configurable from setup viaProperty::from()Handler code cannot tamper with any of these.
Runtime as a library
hyperlight-js-runtimenow exposes a[lib]target. Extender crates depend on it and provide a binary that links everything together. TheHYPERLIGHT_JS_RUNTIME_PATHbuild-time env var tellshyperlight-jsto embed the custom binary.Guest infrastructure (entry point, host function dispatch, libc stubs) moved from
src/main/tosrc/guest/and is provided by the lib — no copying needed.Key changes
src/hyperlight-js-runtime/src/modules/mod.rsNativeModuleLoader,register_native_module,native_modules!,custom_globals!,setup_custom_globals()src/hyperlight-js-runtime/src/lib.rssetup→custom_globals→freezesrc/hyperlight-js-runtime/src/globals/console.rssrc/hyperlight-js-runtime/src/globals/print.rssrc/hyperlight-js-runtime/src/globals/freeze.rssrc/hyperlight-js-runtime/src/globals/mod.rsfreeze()public functionsrc/hyperlight-js-runtime/src/main.rsnative_modules! {}+custom_globals! {}src/hyperlight-js-runtime/src/guest/src/main/hyperlight.rs— lib-provided guest infrasrc/hyperlight-js/build.rsHYPERLIGHT_JS_RUNTIME_PATHsupportdocs/extending-runtime.mdTests
tests/native_modules.rs: loader resolution, custom modules, built-in override,requireprotection,custom_globals!macro, console extensions, freeze behavioursrc/hyperlight-js/tests/native_modules.rs:HYPERLIGHT_JS_RUNTIME_PATHembeddingnative_math(shared lib) +extended_runtime(binary with custom modules + globals)