mirror of
https://github.com/morluto/rea.git
synced 2026-10-29 10:55:57 +00:00
fix(javascript): preserve builtin identity and share alias traversal
Track module writes and escapes at their owner, preserve capture and reassignment ordering, and share CommonJS/default namespace identity without erasing parent-slot changes. Carry write sites into ambient alias resolution and use parsed write targets across consumers. Deduplicate returned-reference work with cycle context; retain unchanged temporal selection identity so provenance memoization stays effective. Reviewed fixes include #2041, #2465, #2830, #2881, and #2948. Remove superseded mutation representations and the ineffective per-markValue dedup layer. Validation: 380 focused JavaScript tests passed under a 384 MiB heap cap, including the previously aborting 30-level/128-call alias regression. Six public CLI/MCP builtin tests passed. Exact pdf.js completed-workflow performance remains unmeasured.
This commit is contained in:
1 parent
0f4c484be5
commit
04672f2b91
34 files changed
+3778
-321
No files matched your search
@@ -0,0 +1,225 @@
|
||||
import * as t from "@babel/types";
|
||||
|
||||
import { javascriptBootstrapAt } from "./javascriptBootstrap.js";
|
||||
import { proveJavaScriptBootstrapIntegrity } from "./javascriptBootstrapIntegrity.js";
|
||||
import { semanticStaticPropertyKey } from "./javascriptAstValues.js";
|
||||
import {
|
||||
semanticMemberChain,
|
||||
semanticRequireOrigin,
|
||||
type JavaScriptRequireOrigin,
|
||||
} from "./javascriptSemanticRequireOrigin.js";
|
||||
import {
|
||||
resolveSemanticBindingState,
|
||||
semanticResolutionBlocked,
|
||||
type JavaScriptSemanticAnalysisState,
|
||||
} from "./javascriptSemanticState.js";
|
||||
import {
|
||||
argumentValue,
|
||||
moduleFactory,
|
||||
modulePropertyName,
|
||||
} from "./javascriptStaticAnalysisHelpers.js";
|
||||
|
||||
/** Loader bindings and literal externals proven for one standalone bootstrap. */
|
||||
interface BootstrapExternals {
|
||||
/** The runtime loader and every factory parameter it is passed as. */
|
||||
readonly loaderBindingIds: ReadonlySet<string>;
|
||||
/** Table keys whose factory only re-exports one unshadowed literal require; null when a key repeats. */
|
||||
readonly externals: ReadonlyMap<string, string | null>;
|
||||
}
|
||||
|
||||
const proofs = new WeakMap<
|
||||
JavaScriptSemanticAnalysisState,
|
||||
WeakMap<t.CallExpression, BootstrapExternals | null>
|
||||
>();
|
||||
|
||||
/**
|
||||
* Recover a literal require reached through a proven Webpack bootstrap.
|
||||
*
|
||||
* Webpack emits externals as `{45840: e => { e.exports = require("electron") }}`
|
||||
* and consumers call the runtime loader, `n(45840)`, instead of `require`. The
|
||||
* origin is accepted only when the loader binding is the bootstrap's own loader
|
||||
* or a factory parameter that the bootstrap proves it passes the loader as, and
|
||||
* the keyed factory consists solely of that re-export.
|
||||
*/
|
||||
export const semanticBundledRequireOrigin = (
|
||||
node: t.Node | null | undefined,
|
||||
state: JavaScriptSemanticAnalysisState,
|
||||
): JavaScriptRequireOrigin | undefined => {
|
||||
const chain = semanticMemberChain(node);
|
||||
const current = chain?.root;
|
||||
if (
|
||||
chain === undefined ||
|
||||
!t.isCallExpression(current) ||
|
||||
!t.isIdentifier(current.callee) ||
|
||||
current.arguments.length !== 1
|
||||
)
|
||||
return undefined;
|
||||
const key = argumentValue(current.arguments[0]);
|
||||
if (key === undefined) return undefined;
|
||||
const loader = current.callee;
|
||||
if (semanticResolutionBlocked(state, loader, loader.name)) return undefined;
|
||||
const binding = resolveSemanticBindingState(state, loader, loader.name);
|
||||
if (
|
||||
binding === undefined ||
|
||||
binding.definitions.length !== 1 ||
|
||||
binding.definitions[0]?.kind === "assignment"
|
||||
)
|
||||
return undefined;
|
||||
for (
|
||||
let ancestor = state.parentsByNode.get(current);
|
||||
ancestor !== undefined;
|
||||
ancestor = state.parentsByNode.get(ancestor)
|
||||
) {
|
||||
if (!t.isCallExpression(ancestor)) continue;
|
||||
const proof = bootstrapExternals(ancestor, state);
|
||||
if (proof === null || !proof.loaderBindingIds.has(binding.bindingId))
|
||||
continue;
|
||||
const specifier = proof.externals.get(key);
|
||||
return typeof specifier === "string"
|
||||
? {
|
||||
origin: {
|
||||
specifier,
|
||||
importedPath: chain.members,
|
||||
resolutionMode: "require",
|
||||
},
|
||||
call: current,
|
||||
}
|
||||
: undefined;
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
const bootstrapExternals = (
|
||||
call: t.CallExpression,
|
||||
state: JavaScriptSemanticAnalysisState,
|
||||
): BootstrapExternals | null => {
|
||||
let byCall = proofs.get(state);
|
||||
if (byCall === undefined) {
|
||||
byCall = new WeakMap();
|
||||
proofs.set(state, byCall);
|
||||
}
|
||||
const cached = byCall.get(call);
|
||||
if (cached !== undefined) return cached;
|
||||
const proof = proveBootstrapExternals(call, state);
|
||||
byCall.set(call, proof);
|
||||
return proof;
|
||||
};
|
||||
|
||||
const proveBootstrapExternals = (
|
||||
call: t.CallExpression,
|
||||
state: JavaScriptSemanticAnalysisState,
|
||||
): BootstrapExternals | null => {
|
||||
const bootstrap = javascriptBootstrapAt(call, state);
|
||||
// A replaced loader no longer dispatches the declared table.
|
||||
if (
|
||||
bootstrap === undefined ||
|
||||
!singleDefinition(state, bootstrap.loaderBindingId, "function")
|
||||
)
|
||||
return null;
|
||||
const loaderBindingIds = new Set([bootstrap.loaderBindingId]);
|
||||
const factories = bootstrap.table.properties.flatMap((property) => {
|
||||
const factory = moduleFactory(property);
|
||||
return factory === undefined ? [] : [{ property, factory }];
|
||||
});
|
||||
for (const { factory } of factories) {
|
||||
// The bootstrap proves `table[key](module, module.exports, loader)`.
|
||||
const loaderParameter = factory.params[2];
|
||||
const bindingId = t.isIdentifier(loaderParameter)
|
||||
? resolveSemanticBindingState(
|
||||
state,
|
||||
loaderParameter,
|
||||
loaderParameter.name,
|
||||
)?.bindingId
|
||||
: undefined;
|
||||
if (
|
||||
bindingId !== undefined &&
|
||||
singleDefinition(state, bindingId, "parameter")
|
||||
)
|
||||
loaderBindingIds.add(bindingId);
|
||||
}
|
||||
const integrity = proveJavaScriptBootstrapIntegrity(
|
||||
call,
|
||||
bootstrap,
|
||||
loaderBindingIds,
|
||||
state,
|
||||
);
|
||||
if (integrity === undefined) return null;
|
||||
const externals = new Map<string, string | null>();
|
||||
for (const { property, factory } of factories) {
|
||||
const key = modulePropertyName(property);
|
||||
const specifier = integrity.replacedKeys.has(key)
|
||||
? undefined
|
||||
: externalSpecifier(factory, state);
|
||||
if (externals.has(key)) externals.set(key, null);
|
||||
else externals.set(key, specifier ?? null);
|
||||
}
|
||||
return { loaderBindingIds, externals };
|
||||
};
|
||||
|
||||
/**
|
||||
* Accept only `module.exports = require("specifier")` as the whole body of an
|
||||
* ordinary factory; generator, async and accessor factories do not run it.
|
||||
*/
|
||||
const externalSpecifier = (
|
||||
factory: t.FunctionExpression | t.ArrowFunctionExpression | t.ObjectMethod,
|
||||
state: JavaScriptSemanticAnalysisState,
|
||||
): string | undefined => {
|
||||
const moduleParameter = factory.params[0];
|
||||
const names = factory.params.map((parameter) =>
|
||||
t.isIdentifier(parameter) ? parameter.name : null,
|
||||
);
|
||||
if (
|
||||
!t.isIdentifier(moduleParameter) ||
|
||||
// A duplicated name binds the later argument, not the module object.
|
||||
new Set(names).size !== names.length ||
|
||||
factory.generator ||
|
||||
factory.async ||
|
||||
(t.isObjectMethod(factory) && factory.kind !== "method")
|
||||
)
|
||||
return undefined;
|
||||
let expression: t.Node | undefined;
|
||||
if (t.isBlockStatement(factory.body)) {
|
||||
const [statement] = factory.body.body;
|
||||
if (factory.body.body.length !== 1 || !t.isExpressionStatement(statement))
|
||||
return undefined;
|
||||
expression = statement.expression;
|
||||
} else expression = factory.body;
|
||||
if (
|
||||
!t.isAssignmentExpression(expression, { operator: "=" }) ||
|
||||
!t.isMemberExpression(expression.left) ||
|
||||
!t.isIdentifier(expression.left.object) ||
|
||||
semanticStaticPropertyKey(
|
||||
expression.left.property,
|
||||
expression.left.computed,
|
||||
) !== "exports"
|
||||
)
|
||||
return undefined;
|
||||
const moduleBinding = resolveSemanticBindingState(
|
||||
state,
|
||||
moduleParameter,
|
||||
moduleParameter.name,
|
||||
);
|
||||
const target = resolveSemanticBindingState(
|
||||
state,
|
||||
expression.left.object,
|
||||
expression.left.object.name,
|
||||
);
|
||||
if (
|
||||
moduleBinding === undefined ||
|
||||
target?.bindingId !== moduleBinding.bindingId
|
||||
)
|
||||
return undefined;
|
||||
const required = semanticRequireOrigin(expression.right, state)?.origin;
|
||||
return required !== undefined && required.importedPath.length === 0
|
||||
? required.specifier
|
||||
: undefined;
|
||||
};
|
||||
|
||||
const singleDefinition = (
|
||||
state: JavaScriptSemanticAnalysisState,
|
||||
bindingId: string,
|
||||
kind: "function" | "parameter",
|
||||
): boolean => {
|
||||
const definitions = state.bindingsById.get(bindingId)?.definitions;
|
||||
return definitions?.length === 1 && definitions[0]?.kind === kind;
|
||||
};
|
||||
Reference in new issue
Block a user