VM: fix nested IO suspension frame corruption, island hydration preload
VM frame merging bug: call_closure_reuse now saves caller continuations on a reuse_stack instead of merging frames. resume_vm restores them in innermost-first order. Fixes frame count corruption when nested closures suspend via OP_PERFORM. Zero test regressions (3924/3924). Island hydration: hydrate-island now looks up components from (global-env) instead of render-env, triggering the symbol resolve hook. Added JS-level preload-island-defs that scans DOM for data-sx-island and loads definitions from the content-addressed manifest BEFORE hydration — avoids K.load reentrancy when the resolve hook fires inside env_get. loadDefinitionByHash: fixed isMultiDefine check — defcomp/defisland bodies containing nested (define ...) forms no longer suppress name insertion. Added K.load return value checking for silent error string returns. sx_browser.ml: resolve hook falls back to global_env.bindings when _vm_globals miss (sync gap). Snapshot reuse_stack alongside pending_cek. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -846,7 +846,11 @@
|
||||
// already contain named (define name ...) forms.
|
||||
var name = _hashToName[hash];
|
||||
if (name) {
|
||||
var isMultiDefine = /\(define\s+[a-zA-Z]/.test(rewritten);
|
||||
// Check if this is a multi-define file (client lib with top-level defines).
|
||||
// Only top-level (define ...) forms count — nested ones inside defisland/defcomp
|
||||
// bodies should NOT suppress name insertion.
|
||||
var startsWithDef = /^\((defcomp|defisland|defmacro)\s/.test(rewritten);
|
||||
var isMultiDefine = !startsWithDef && /\(define\s+[a-zA-Z]/.test(rewritten);
|
||||
if (!isMultiDefine) {
|
||||
rewritten = rewritten.replace(
|
||||
/^\((defcomp|defisland|defmacro|define)\s/,
|
||||
@@ -856,7 +860,12 @@
|
||||
}
|
||||
|
||||
try {
|
||||
K.load(rewritten);
|
||||
var loadRv = K.load(rewritten);
|
||||
if (typeof loadRv === "string" && loadRv.indexOf("Error") >= 0) {
|
||||
console.warn("[sx] K.load error for", (_hashToName[hash] || hash) + ":", loadRv);
|
||||
delete _loadedHashes[hash];
|
||||
return false;
|
||||
}
|
||||
_loadedHashes[hash] = true;
|
||||
return true;
|
||||
} catch(e) {
|
||||
@@ -865,11 +874,28 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Eagerly pre-load island definitions from the manifest.
|
||||
// Called from boot.sx before hydration. Scans the DOM for data-sx-island
|
||||
// attributes and loads definitions via the content-addressed manifest.
|
||||
// Unlike __resolve-symbol (called from inside env_get), this runs at the
|
||||
// top level so K.load can register bindings without reentrancy issues.
|
||||
K.registerNative("preload-island-defs", function() {
|
||||
var manifest = loadPageManifest();
|
||||
if (!manifest || !manifest.defs) return null;
|
||||
var els = document.querySelectorAll('[data-sx-island]');
|
||||
for (var i = 0; i < els.length; i++) {
|
||||
var name = "~" + els[i].getAttribute("data-sx-island");
|
||||
if (manifest.defs[name] && !_loadedHashes[manifest.defs[name]]) {
|
||||
loadDefinitionByHash(manifest.defs[name]);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
// Register the resolve hook — called by the VM when GLOBAL_GET fails
|
||||
K.registerNative("__resolve-symbol", function(args) {
|
||||
var name = args[0];
|
||||
if (!name) return null;
|
||||
|
||||
// Content-addressed resolution — components, libraries, macros
|
||||
var manifest = loadPageManifest();
|
||||
if (manifest && manifest.defs && manifest.defs[name]) {
|
||||
@@ -918,6 +944,20 @@
|
||||
K.eval("(process-sx-scripts nil)");
|
||||
console.log("[sx] sx-hydrate-elements...");
|
||||
K.eval("(sx-hydrate-elements nil)");
|
||||
// Pre-load island definitions from manifest before hydration.
|
||||
// Must happen at JS level (not from inside SX eval) to avoid
|
||||
// K.load reentrancy issues with the symbol resolve hook.
|
||||
var manifest = loadPageManifest();
|
||||
if (manifest && manifest.defs) {
|
||||
var islandEls = document.querySelectorAll("[data-sx-island]");
|
||||
for (var ii = 0; ii < islandEls.length; ii++) {
|
||||
var iname = "~" + islandEls[ii].getAttribute("data-sx-island");
|
||||
var ihash = manifest.defs[iname];
|
||||
if (ihash && !_loadedHashes[ihash]) {
|
||||
loadDefinitionByHash(ihash);
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log("[sx] sx-hydrate-islands...");
|
||||
K.eval("(sx-hydrate-islands nil)");
|
||||
console.log("[sx] process-elements...");
|
||||
|
||||
Reference in New Issue
Block a user