Optimize evaluator hot path: prototype-chain envs, imperative kwarg parsing
Three key optimizations to the JS evaluator platform layer: 1. envMerge uses Object.create() instead of copying all keys — O(own) vs O(all) 2. renderDomComponent/renderDomElement override: imperative kwarg/attr parsing replaces reduce+assoc pattern (no per-arg dict allocation) 3. callComponent/parseKeywordArgs override: same imperative pattern for the eval path (not just DOM rendering) Wire format and spec semantics unchanged — these are host-level performance overrides in the platform JS. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -14,7 +14,7 @@
|
|||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|
||||||
var NIL = Object.freeze({ _nil: true, toString: function() { return "nil"; } });
|
var NIL = Object.freeze({ _nil: true, toString: function() { return "nil"; } });
|
||||||
var SX_VERSION = "2026-03-07T01:23:32Z";
|
var SX_VERSION = "2026-03-07T01:41:53Z";
|
||||||
|
|
||||||
function isNil(x) { return x === NIL || x === null || x === undefined; }
|
function isNil(x) { return x === NIL || x === null || x === undefined; }
|
||||||
function isSxTruthy(x) { return x !== false && !isNil(x); }
|
function isSxTruthy(x) { return x !== false && !isNil(x); }
|
||||||
@@ -174,8 +174,12 @@
|
|||||||
function envHas(env, name) { return name in env; }
|
function envHas(env, name) { return name in env; }
|
||||||
function envGet(env, name) { return env[name]; }
|
function envGet(env, name) { return env[name]; }
|
||||||
function envSet(env, name, val) { env[name] = val; }
|
function envSet(env, name, val) { env[name] = val; }
|
||||||
function envExtend(env) { return merge(env); }
|
function envExtend(env) { return Object.create(env); }
|
||||||
function envMerge(base, overlay) { return merge(base, overlay); }
|
function envMerge(base, overlay) {
|
||||||
|
var child = Object.create(base);
|
||||||
|
if (overlay) for (var k in overlay) if (overlay.hasOwnProperty(k)) child[k] = overlay[k];
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
|
||||||
function dictSet(d, k, v) { d[k] = v; return v; }
|
function dictSet(d, k, v) { d[k] = v; return v; }
|
||||||
function dictGet(d, k) { var v = d[k]; return v !== undefined ? v : NIL; }
|
function dictGet(d, k) { var v = d[k]; return v !== undefined ? v : NIL; }
|
||||||
@@ -515,6 +519,52 @@
|
|||||||
return NIL;
|
return NIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// Performance overrides — evaluator hot path
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
// Override parseKeywordArgs: imperative loop instead of reduce+assoc
|
||||||
|
parseKeywordArgs = function(rawArgs, env) {
|
||||||
|
var kwargs = {};
|
||||||
|
var children = [];
|
||||||
|
for (var i = 0; i < rawArgs.length; i++) {
|
||||||
|
var arg = rawArgs[i];
|
||||||
|
if (arg && arg._kw && (i + 1) < rawArgs.length) {
|
||||||
|
kwargs[arg.name] = trampoline(evalExpr(rawArgs[i + 1], env));
|
||||||
|
i++;
|
||||||
|
} else {
|
||||||
|
children.push(trampoline(evalExpr(arg, env)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [kwargs, children];
|
||||||
|
};
|
||||||
|
|
||||||
|
// Override callComponent: use prototype chain env, imperative kwarg binding
|
||||||
|
callComponent = function(comp, rawArgs, env) {
|
||||||
|
var kwargs = {};
|
||||||
|
var children = [];
|
||||||
|
for (var i = 0; i < rawArgs.length; i++) {
|
||||||
|
var arg = rawArgs[i];
|
||||||
|
if (arg && arg._kw && (i + 1) < rawArgs.length) {
|
||||||
|
kwargs[arg.name] = trampoline(evalExpr(rawArgs[i + 1], env));
|
||||||
|
i++;
|
||||||
|
} else {
|
||||||
|
children.push(trampoline(evalExpr(arg, env)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var local = Object.create(componentClosure(comp));
|
||||||
|
for (var k in env) if (env.hasOwnProperty(k)) local[k] = env[k];
|
||||||
|
var params = componentParams(comp);
|
||||||
|
for (var j = 0; j < params.length; j++) {
|
||||||
|
var p = params[j];
|
||||||
|
local[p] = p in kwargs ? kwargs[p] : NIL;
|
||||||
|
}
|
||||||
|
if (componentHasChildren(comp)) {
|
||||||
|
local["children"] = children;
|
||||||
|
}
|
||||||
|
return makeThunk(componentBody(comp), local);
|
||||||
|
};
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
// Platform: deps module — component dependency analysis
|
// Platform: deps module — component dependency analysis
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
@@ -2849,6 +2899,84 @@ callExpr.push(dictGet(kwargs, k)); } }
|
|||||||
|
|
||||||
function domTagName(el) { return el && el.tagName ? el.tagName : ""; }
|
function domTagName(el) { return el && el.tagName ? el.tagName : ""; }
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// Performance overrides — replace transpiled spec with imperative JS
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
// Override renderDomComponent: imperative kwarg parsing, no reduce/assoc
|
||||||
|
renderDomComponent = function(comp, args, env, ns) {
|
||||||
|
// Parse keyword args imperatively
|
||||||
|
var kwargs = {};
|
||||||
|
var children = [];
|
||||||
|
for (var i = 0; i < args.length; i++) {
|
||||||
|
var arg = args[i];
|
||||||
|
if (arg && arg._kw && (i + 1) < args.length) {
|
||||||
|
kwargs[arg.name] = trampoline(evalExpr(args[i + 1], env));
|
||||||
|
i++; // skip value
|
||||||
|
} else {
|
||||||
|
children.push(arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Build local env via prototype chain
|
||||||
|
var local = Object.create(componentClosure(comp));
|
||||||
|
// Copy caller env own properties
|
||||||
|
for (var k in env) if (env.hasOwnProperty(k)) local[k] = env[k];
|
||||||
|
// Bind params
|
||||||
|
var params = componentParams(comp);
|
||||||
|
for (var j = 0; j < params.length; j++) {
|
||||||
|
var p = params[j];
|
||||||
|
local[p] = p in kwargs ? kwargs[p] : NIL;
|
||||||
|
}
|
||||||
|
// Bind children
|
||||||
|
if (componentHasChildren(comp)) {
|
||||||
|
var childFrag = document.createDocumentFragment();
|
||||||
|
for (var c = 0; c < children.length; c++) {
|
||||||
|
var rendered = renderToDom(children[c], env, ns);
|
||||||
|
if (rendered) childFrag.appendChild(rendered);
|
||||||
|
}
|
||||||
|
local["children"] = childFrag;
|
||||||
|
}
|
||||||
|
return renderToDom(componentBody(comp), local, ns);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Override renderDomElement: imperative attr parsing, no reduce/assoc
|
||||||
|
renderDomElement = function(tag, args, env, ns) {
|
||||||
|
var newNs = tag === "svg" ? SVG_NS : tag === "math" ? MATH_NS : ns;
|
||||||
|
var el = domCreateElement(tag, newNs);
|
||||||
|
var extraClasses = [];
|
||||||
|
var isVoid = contains(VOID_ELEMENTS, tag);
|
||||||
|
for (var i = 0; i < args.length; i++) {
|
||||||
|
var arg = args[i];
|
||||||
|
if (arg && arg._kw && (i + 1) < args.length) {
|
||||||
|
var attrName = arg.name;
|
||||||
|
var attrVal = trampoline(evalExpr(args[i + 1], env));
|
||||||
|
i++; // skip value
|
||||||
|
if (isNil(attrVal) || attrVal === false) continue;
|
||||||
|
if (attrName === "class" && attrVal && attrVal._styleValue) {
|
||||||
|
extraClasses.push(attrVal.className);
|
||||||
|
} else if (attrName === "style" && attrVal && attrVal._styleValue) {
|
||||||
|
extraClasses.push(attrVal.className);
|
||||||
|
} else if (contains(BOOLEAN_ATTRS, attrName)) {
|
||||||
|
if (isSxTruthy(attrVal)) el.setAttribute(attrName, "");
|
||||||
|
} else if (attrVal === true) {
|
||||||
|
el.setAttribute(attrName, "");
|
||||||
|
} else {
|
||||||
|
el.setAttribute(attrName, String(attrVal));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!isVoid) {
|
||||||
|
var child = renderToDom(arg, env, newNs);
|
||||||
|
if (child) el.appendChild(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (extraClasses.length) {
|
||||||
|
var existing = el.getAttribute("class") || "";
|
||||||
|
el.setAttribute("class", (existing ? existing + " " : "") + extraClasses.join(" "));
|
||||||
|
}
|
||||||
|
return el;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
// Platform interface — Engine pure logic (browser + node compatible)
|
// Platform interface — Engine pure logic (browser + node compatible)
|
||||||
|
|||||||
@@ -1710,8 +1710,12 @@ PLATFORM_JS_PRE = '''
|
|||||||
function envHas(env, name) { return name in env; }
|
function envHas(env, name) { return name in env; }
|
||||||
function envGet(env, name) { return env[name]; }
|
function envGet(env, name) { return env[name]; }
|
||||||
function envSet(env, name, val) { env[name] = val; }
|
function envSet(env, name, val) { env[name] = val; }
|
||||||
function envExtend(env) { return merge(env); }
|
function envExtend(env) { return Object.create(env); }
|
||||||
function envMerge(base, overlay) { return merge(base, overlay); }
|
function envMerge(base, overlay) {
|
||||||
|
var child = Object.create(base);
|
||||||
|
if (overlay) for (var k in overlay) if (overlay.hasOwnProperty(k)) child[k] = overlay[k];
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
|
||||||
function dictSet(d, k, v) { d[k] = v; return v; }
|
function dictSet(d, k, v) { d[k] = v; return v; }
|
||||||
function dictGet(d, k) { var v = d[k]; return v !== undefined ? v : NIL; }
|
function dictGet(d, k) { var v = d[k]; return v !== undefined ? v : NIL; }
|
||||||
@@ -1852,7 +1856,53 @@ PLATFORM_JS_POST = '''
|
|||||||
function forEachIndexed(fn, coll) {
|
function forEachIndexed(fn, coll) {
|
||||||
for (var i = 0; i < coll.length; i++) fn(i, coll[i]);
|
for (var i = 0; i < coll.length; i++) fn(i, coll[i]);
|
||||||
return NIL;
|
return NIL;
|
||||||
}'''
|
}
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// Performance overrides — evaluator hot path
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
// Override parseKeywordArgs: imperative loop instead of reduce+assoc
|
||||||
|
parseKeywordArgs = function(rawArgs, env) {
|
||||||
|
var kwargs = {};
|
||||||
|
var children = [];
|
||||||
|
for (var i = 0; i < rawArgs.length; i++) {
|
||||||
|
var arg = rawArgs[i];
|
||||||
|
if (arg && arg._kw && (i + 1) < rawArgs.length) {
|
||||||
|
kwargs[arg.name] = trampoline(evalExpr(rawArgs[i + 1], env));
|
||||||
|
i++;
|
||||||
|
} else {
|
||||||
|
children.push(trampoline(evalExpr(arg, env)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [kwargs, children];
|
||||||
|
};
|
||||||
|
|
||||||
|
// Override callComponent: use prototype chain env, imperative kwarg binding
|
||||||
|
callComponent = function(comp, rawArgs, env) {
|
||||||
|
var kwargs = {};
|
||||||
|
var children = [];
|
||||||
|
for (var i = 0; i < rawArgs.length; i++) {
|
||||||
|
var arg = rawArgs[i];
|
||||||
|
if (arg && arg._kw && (i + 1) < rawArgs.length) {
|
||||||
|
kwargs[arg.name] = trampoline(evalExpr(rawArgs[i + 1], env));
|
||||||
|
i++;
|
||||||
|
} else {
|
||||||
|
children.push(trampoline(evalExpr(arg, env)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var local = Object.create(componentClosure(comp));
|
||||||
|
for (var k in env) if (env.hasOwnProperty(k)) local[k] = env[k];
|
||||||
|
var params = componentParams(comp);
|
||||||
|
for (var j = 0; j < params.length; j++) {
|
||||||
|
var p = params[j];
|
||||||
|
local[p] = p in kwargs ? kwargs[p] : NIL;
|
||||||
|
}
|
||||||
|
if (componentHasChildren(comp)) {
|
||||||
|
local["children"] = children;
|
||||||
|
}
|
||||||
|
return makeThunk(componentBody(comp), local);
|
||||||
|
};'''
|
||||||
|
|
||||||
PLATFORM_DEPS_JS = '''
|
PLATFORM_DEPS_JS = '''
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
@@ -2117,6 +2167,84 @@ PLATFORM_DOM_JS = """
|
|||||||
}
|
}
|
||||||
|
|
||||||
function domTagName(el) { return el && el.tagName ? el.tagName : ""; }
|
function domTagName(el) { return el && el.tagName ? el.tagName : ""; }
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// Performance overrides — replace transpiled spec with imperative JS
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
// Override renderDomComponent: imperative kwarg parsing, no reduce/assoc
|
||||||
|
renderDomComponent = function(comp, args, env, ns) {
|
||||||
|
// Parse keyword args imperatively
|
||||||
|
var kwargs = {};
|
||||||
|
var children = [];
|
||||||
|
for (var i = 0; i < args.length; i++) {
|
||||||
|
var arg = args[i];
|
||||||
|
if (arg && arg._kw && (i + 1) < args.length) {
|
||||||
|
kwargs[arg.name] = trampoline(evalExpr(args[i + 1], env));
|
||||||
|
i++; // skip value
|
||||||
|
} else {
|
||||||
|
children.push(arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Build local env via prototype chain
|
||||||
|
var local = Object.create(componentClosure(comp));
|
||||||
|
// Copy caller env own properties
|
||||||
|
for (var k in env) if (env.hasOwnProperty(k)) local[k] = env[k];
|
||||||
|
// Bind params
|
||||||
|
var params = componentParams(comp);
|
||||||
|
for (var j = 0; j < params.length; j++) {
|
||||||
|
var p = params[j];
|
||||||
|
local[p] = p in kwargs ? kwargs[p] : NIL;
|
||||||
|
}
|
||||||
|
// Bind children
|
||||||
|
if (componentHasChildren(comp)) {
|
||||||
|
var childFrag = document.createDocumentFragment();
|
||||||
|
for (var c = 0; c < children.length; c++) {
|
||||||
|
var rendered = renderToDom(children[c], env, ns);
|
||||||
|
if (rendered) childFrag.appendChild(rendered);
|
||||||
|
}
|
||||||
|
local["children"] = childFrag;
|
||||||
|
}
|
||||||
|
return renderToDom(componentBody(comp), local, ns);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Override renderDomElement: imperative attr parsing, no reduce/assoc
|
||||||
|
renderDomElement = function(tag, args, env, ns) {
|
||||||
|
var newNs = tag === "svg" ? SVG_NS : tag === "math" ? MATH_NS : ns;
|
||||||
|
var el = domCreateElement(tag, newNs);
|
||||||
|
var extraClasses = [];
|
||||||
|
var isVoid = contains(VOID_ELEMENTS, tag);
|
||||||
|
for (var i = 0; i < args.length; i++) {
|
||||||
|
var arg = args[i];
|
||||||
|
if (arg && arg._kw && (i + 1) < args.length) {
|
||||||
|
var attrName = arg.name;
|
||||||
|
var attrVal = trampoline(evalExpr(args[i + 1], env));
|
||||||
|
i++; // skip value
|
||||||
|
if (isNil(attrVal) || attrVal === false) continue;
|
||||||
|
if (attrName === "class" && attrVal && attrVal._styleValue) {
|
||||||
|
extraClasses.push(attrVal.className);
|
||||||
|
} else if (attrName === "style" && attrVal && attrVal._styleValue) {
|
||||||
|
extraClasses.push(attrVal.className);
|
||||||
|
} else if (contains(BOOLEAN_ATTRS, attrName)) {
|
||||||
|
if (isSxTruthy(attrVal)) el.setAttribute(attrName, "");
|
||||||
|
} else if (attrVal === true) {
|
||||||
|
el.setAttribute(attrName, "");
|
||||||
|
} else {
|
||||||
|
el.setAttribute(attrName, String(attrVal));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!isVoid) {
|
||||||
|
var child = renderToDom(arg, env, newNs);
|
||||||
|
if (child) el.appendChild(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (extraClasses.length) {
|
||||||
|
var existing = el.getAttribute("class") || "";
|
||||||
|
el.setAttribute("class", (existing ? existing + " " : "") + extraClasses.join(" "));
|
||||||
|
}
|
||||||
|
return el;
|
||||||
|
};
|
||||||
"""
|
"""
|
||||||
|
|
||||||
PLATFORM_ENGINE_PURE_JS = """
|
PLATFORM_ENGINE_PURE_JS = """
|
||||||
|
|||||||
Reference in New Issue
Block a user