VM import suspension for browser lazy loading
Bytecode compiler now emits OP_PERFORM for (import ...) and compiles
(define-library ...) bodies. The VM stores the import request in
globals["__io_request"] and stops the run loop — no exceptions needed.
vm-execute-module returns a suspension dict, vm-resume-module continues.
Browser: sx_browser.ml detects suspension dicts from execute_module and
returns JS {suspended, op, request, resume} objects. The sx-platform.js
while loop handles cascading suspensions via handleImportSuspension.
13 modules load via .sxbc bytecode in 226ms (manifest-driven), both
islands hydrate, all handlers wired. 2650/2650 tests pass including
6 new vm-import-suspension tests.
Also: consolidated sx-platform-2.js → sx-platform.js, fixed
vm-execute-module missing code-from-value call, fixed bootstrap.py
protocol registry transpiler issues.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -70,37 +70,26 @@ for (const file of FILES) {
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Strip define-library/import wrappers for bytecode compilation.
|
||||
// Strip define-library wrapper for bytecode compilation.
|
||||
//
|
||||
// The VM's execute_module doesn't handle define-library or import — they're
|
||||
// CEK special forms. So the compiled bytecode should contain just the body
|
||||
// defines. The eval-blob phase (above) already handled library registration
|
||||
// via CEK. The JS loader pre-resolves deps, so no registry needed at runtime.
|
||||
// Keeps (import ...) forms — the compiler emits OP_PERFORM for these, enabling
|
||||
// lazy loading: when the VM hits an import for an unloaded library, it suspends
|
||||
// to the JS platform which fetches the library on demand.
|
||||
//
|
||||
// Strips define-library header (name, export) and (begin ...) wrapper, leaving
|
||||
// the body defines + import instructions as top-level forms.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function stripLibraryWrapper(source) {
|
||||
// Line-based stripping: remove (import ...), unwrap (define-library ... (begin BODY)).
|
||||
// Works with both pre-existing and newly-wrapped formats.
|
||||
// Line-based stripping: unwrap (define-library ... (begin BODY)), keep (import ...).
|
||||
const lines = source.split('\n');
|
||||
const result = [];
|
||||
let skip = false; // inside header region (define-library, export)
|
||||
let importDepth = 0; // tracking multi-line import paren depth
|
||||
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const line = lines[i];
|
||||
const trimmed = line.trim();
|
||||
|
||||
// Skip (import ...) — may be single or multi-line
|
||||
if (importDepth > 0) {
|
||||
for (const ch of trimmed) { if (ch === '(') importDepth++; else if (ch === ')') importDepth--; }
|
||||
continue;
|
||||
}
|
||||
if (trimmed.startsWith('(import ')) {
|
||||
importDepth = 0;
|
||||
for (const ch of trimmed) { if (ch === '(') importDepth++; else if (ch === ')') importDepth--; }
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip (define-library ...) header lines until (begin
|
||||
if (trimmed.startsWith('(define-library ')) { skip = true; continue; }
|
||||
if (skip && trimmed.startsWith('(export')) { continue; }
|
||||
|
||||
Reference in New Issue
Block a user